2020/04/01

RustのsubsliceでちょこっとL99問題を試してみる 〜その2〜

前回の続き

前回はL-04までやりましたので、今回はL-05から試してみようと思います。
第5問目。「リストを逆順にする関数」の作成。OCamlのコードは以下。

let rev list =
  let rec aux acc = function
    | [] -> acc
    | hd :: tl -> aux (hd::acc) tl in
  aux [] list
;;
与えられたリストの先頭をaccの先頭に追加していくという形。
OCamlでは::があって、Lispと同様コンスできるのですが、Rustにはない。そのかわり、Vecにはinsertという関数があり、指定したインデックスに値を挿入できるので、これを使ってみようと思います。
Rustでは以下のような感じになりました。

fn rev(list: &[i32]) -> Vec<i32> {
    let mut result: Vec<i32> = vec![];

    fn aux(acc: &mut Vec<i32>, l: &[i32]) {
        match l {
            [] => {},
            [hd, tl @ ..] => {
                acc.insert(0, *hd);
                aux(acc, tl);
            }
        }
    }
    aux(&mut result, list);
    result.to_vec()
}
前回同様、関数内関数の形になりました。insertの部分では常に先頭に挿入するように、インデックスを0としています。
続いて第6問目。「回文になっているかどうかを判定する関数」の作成。これは上記の逆順にする関数を使用して以下のような簡単なものになります。

fn is_palindrome(list: &[i32]) -> bool {
    list == &*(rev(list))
}
revの戻り値の型をVecにしたので、&*(rev(list))というややこしい形になってしまいました。このあたり、私のRustの知識、いやプログラミングの知識のなさが露呈してしまっている感が否めませんが、気にせず進みます。
第7問目。「ネストされているリストをネストのないリストへ変換する関数」を作成。
OCamlのコードは以下。

type 'a node =
  | One of 'a
  | Many of 'a node list

let flatten list =
  let rec aux acc = function
    | [] -> acc
    | One x :: tl -> aux (x::acc) tl
    | Many l :: tl -> aux (aux acc l) tl in
  List.rev (aux [] list)
;;
まずネストされたリストを作成するためにnodeというバリアント型を作成。それをflattenしていきます。Rustでやってみると、

enum Node {
    One(i32),
    Many(Vec),
}

fn flatten(list: &[Node]) -> Vec<i32> {
    let mut result: Vec<i32> = vec![];
    fn aux(acc: &mut Vec<i32>, l: &[Node]) {
        match l {
            [] => {},
            [Node::One(x), tl @ ..] => {
                acc.insert(0, *x);
                aux(acc, tl);
            },
            [Node::Many(l), tl @ ..] => {
                aux(acc, l);
                aux(acc, tl);
            }
        }      
    }
    aux(&mut result, list);
    rev(&result).to_vec()
}
Rustではまずenumを使ってOCamlのバリアント型と同様のものを作成し、同様の処理を行っていきます。revはこの記事の最初で作った関数を使用しました。

まとめ

徐々に怪しいコードとなって参りました。さらに言うならば、今の所i32しか使っていないという非常に限られた範囲でしか使うことができないコードを書いてしまっています。おそらくすべての型でうまく動作させるためには、もっとコード量が増えることでしょう。
ひどいコードですが、皆様のRust学習の足しになれば幸いです。

合わせて読みたい記事