Rust自虐旅程(一)-- Curry and Compose

Rust自虐旅程(一)-- Curry and Compose

來自專欄 輝夜的NEET角落

最近在乘著上司要我幫前端那邊寫Redux,反而能空出時間搗鼓Rust,被各種生命週期幹得死來活去,然後總算能寫點小工具了,之後我就想寫寫函數式那邊的工具

在寫前先祭出冰冰的一篇博文:

ice1000.org

嗯,有點基本的東西了,起碼有Option<T>和Result<O, E>,但一些基本工具的缺失還是讓我寫程序時不太爽,我這裡提供一點思路,因為我還沒寫出真的能用的版本

閱讀此系列文章能力要求:

  1. 基本了解Rust語法
  2. 基本了解函數式編程的常用工具
  3. <del>智力</del>

正文

在說typeclass那些之前,先說點基本的,如function curry/compose

我先說已經寫了雛形的compose

use std::ops::BitOr; //用以支持Compose(f1) | f2 | f3...pub struct Compose<T, U>(Box<Fn(T) -> U>); //其實FnMut也行,可是FnOnce不行,FnOnce必須用FnBoximpl<T, U> Compose<T, U> { pub fn new<F>(f: F) -> Compose<T, U> where F: Fn(T) -> U + static { Compose(Box::new(move |x| f(x))) } pub fn call(&self, arg: T) -> U { self.0(arg) }}impl<T, U, V, F> BitOr<F> for Compose<T, U> where T: static, U: static, V: static, F: Fn(U) -> V + static{ type Output = Compose<T, V>; fn bitor(self, rhs: F) -> Compose<T, V> { let f = move |x| self.0(x); Compose(Box::new(move |x| rhs(f(x)))) }}fn main() { let a = " I will be the best "; let f= Compose::new(|x: &str| x.replace(l, "~")) | (|x: String| x.len()) | (|x: usize| x & 1); println!("{:?}", f.call(a)); println!("{:?}", a);}

其實正確的做法應該是用macro,示例如下:

macros_rule! compose { ([ $( $t:item ),* ]) => {/*do wtf you want...*/}}fn main() { let f = compose!( (|x| x+1), //... );}

不過還在研究怎寫,另外用Rust 1.26的return impl trait的syntax sugar應該能處理掉FnOnce

好了,到Curry了,大家猜猜能怎麼做?

.........

答案是:你只能手寫closure,不能自動推導

原因:在safe的層面暫時沒有辦法得知函數簽名,沒有必要的話我不打算降級到unsafe處理

你可以透過寫curry1/curry2/curry3等限定了參數數量與位置的輔助方式寫curry,自動推導?沒門,或者你可以參考C++的std::bind?

先把compose的macro寫好,再來是喜聞樂見的typeclass: Functor/Applicative/Monad

然而Rust沒有Rank-N Types……

下一篇如無意外就是發佈包含了compose macro的KaguyaRs庫,之後才慢慢填typeclass的坑


推薦閱讀:

第四屆函數式編程分享會
最近留意的幾個Conf
想學函數式編程? - 收藏集 - 掘金

TAG:Rust編程語言 | 函數式編程 |