Open14
Rustの書き方メモ
ちょっとした勉強のためメモを残していく
カリー化
closureを返す関数を作る
fn add(x: isize) -> Box<dyn Fn(isize) -> isize> {
Box::new(move |y| x + y)
}
fn main() {
let a = add(1);
let b = a(2);
println!("{b}");
}
Fnはトレイトのため、型として記述する際はBoxで包む必要がある
再帰関数
match式を使って基底部と再帰部を定義する
fn fac(n: usize) -> usize {
match n {
0 => 1,
_ => n * fac(n-1),
}
}
fn main() {
let a = 0;
let b = 3;
println!("{}", fac(a));
println!("{}", fac(b));
}
多重再帰
フィボナッチ数列のn番目の数を求める関数
fn fib(n: usize) -> usize {
match n {
0 => 0,
1 => 1,
_ => fib(n-2) + fib(n-1),
}
}
fn main() {
println!("{}", fib(6));
}
相互再帰
整数nの偶奇判定
fn even(n: usize) -> bool {
match n {
0 => true,
_ => odd(n-1),
}
}
fn odd(n: usize) -> bool {
match n {
0 => false,
_ => even(n-1),
}
}
fn main() {
println!("{}", even(6));
println!("{}", even(3));
println!("{}", odd(5));
println!("{}", odd(4))
}
関数合成
pub fn compose<A, B, C, F, G>(
f: F,
g: G,
) -> impl Fn(A) -> C
where
F: Fn(B) -> C,
G: Fn(A) -> B,
{
move |x| f(g(x))
}
fn main() {
let multiply_and_add = compose(|x| x * 2, |x| x + 2);
println!("{}", multiply_and_add(1));
}
Haskellの
inc :: [Int] -> [Int]
inc [] = []
inc (n:ns) = n+1 : inc ns
をRustで書くと
fn inc(x: &Vec<isize>) -> Vec<isize> {
match x.as_slice() {
[] => vec![],
[head, rest @ ..] => {
let mut result = vec![head+1];
result.append(&mut inc(&rest.to_vec()));
result
},
}
}
もう少しスッキリした書き方はできないものか
この関数部分(+1のとこ)を抽象化するとmapになるらしい
fn map<A, B, F>(f: F, x: &Vec<A>) -> Vec<B>
where
A: Clone,
F: Fn(&A) -> B,
{
match x.as_slice() {
[] => vec![],
[head, rest @ ..] => {
let mut result = vec![f(head)];
result.append(&mut map(f, &rest.to_vec()));
result
}
}
}
この書き方が正しいかはちょっと自信ない・・・
このような、データ構造の中の各要素に関数を適用するmap関数を提供する型クラス(Rustだとトレイト?)を関手(functor)と呼ぶらしい
関手(Functor)
pub trait Functor {
type A;
type Wrapped<B>: Functor;
fn fmap<F, B>(self, f: F) -> Self::Wrapped<B>
where
// ここのトレイト境界、人によってFnOnceにしていたりFnMutにしていたりする
F: Fn(Self::A) -> B;
}
Fのトレイト境界はどうするべきだろう(FnMutにした方が汎用性は高い?)
実装はこんな感じ?
enum Maybe<A> {
Just(A),
Nothing,
}
impl<A> Functor for Maybe<A> {
type A = A;
type Wrapped<B> = Maybe<B>;
fn fmap<F, B>(self, f: F) -> Self::Wrapped<B>
where
F: Fn(Self::A) -> B {
match self {
Maybe::Just(x) => Maybe::Just(f(x)),
Maybe::Nothing => Maybe::Nothing,
}
}
}