mat*_*wko 5 f# ocaml haskell functional-programming
最近,我发现了一种编程样式,这种样式在函数世界中非常有用(而且很漂亮),称为“ 面向铁路的编程”。例如,当要创建产生选项类型的函数的管道时,如果其中任何一个失败,我们都希望返回None,则可以执行以下操作:
someOptionValue // : 'a option
>>= func1 // func1: 'a -> 'b option
>>= func2 // func2: 'b -> 'c option
and so on...
Run Code Online (Sandbox Code Playgroud)
其中,(>>=) : 'a option -> (a' -> 'b option) -> 'b option经营者申请一个价值的左手侧,如果它Some value或None以其他方式。
但是,这里是我的问题,如果我们有一个功能,“以”两个(或多个)选项类型,让说funcAB : 'a -> 'b -> 'c option,valA : 'a option和valB : 'b option我们仍然要创建这个管道,或者使用一些不错的运算符(不创建一个新的专门为这个,但是使用一些标准方法,特别是我不想使用match ... with“解压”选项值)
目前我有这样的事情:
valA
>>= (funcAB >> Some)
>>= (fun ctr -> valB >>= ctr)
Run Code Online (Sandbox Code Playgroud)
但是,这似乎不是“正确的”(或者,“ fun”是更好的词;]),并且如果函数需要更多参数或者我们想要创建更长的管道,它的伸缩性也不佳。有一个更好的方法吗?
我使用了F#语法,但是我认为这个问题可以应用于任何功能性编程语言,例如OCaml和Haskell。
编辑(解决方案):
感谢chi的回答,我创建了以下代码F#,它比我以前的代码更加习惯:
funcAB <!> valA <*> valB |> Option.flatten
Run Code Online (Sandbox Code Playgroud)
如果我们有更多的价值,它看起来很好:funcAB <!> valA <*> valB <*> valC <*> ...。
我使用了YoLo中定义的运算符。
在Haskell中,我们可以使用以下Applicative语法:
如果
valA :: f a
valB :: f b
funAB :: a -> b -> f c
Run Code Online (Sandbox Code Playgroud)
然后
join $ funAB <$> valA <*> valB :: f c
Run Code Online (Sandbox Code Playgroud)
提供的f是monad(例如Maybe,Haskell的option)。
我猜,只要您定义运算符,它也应该适用于F#
(<$>) :: (a -> b) -> f a -> f b
(<*>) :: f (a -> b) -> f a -> f b
join :: f (f a) -> f a
Run Code Online (Sandbox Code Playgroud)
上面的技巧是一个穷人版本的Idris!-notation(爆炸符号)。
另一个常见的选择是使用 do
do a <- valA
b <- valB
funAB a b
Run Code Online (Sandbox Code Playgroud)
但这>>=确实与使用相当:
valA >>= \a ->
valB >>= \b ->
funAB a b
Run Code Online (Sandbox Code Playgroud)
并不复杂。