将两个(或多个)选项值应用于F#中的函数的正确方法

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 valueNone以其他方式。

但是,这里是我的问题,如果我们有一个功能,“以”两个(或多个)选项类型,让说funcAB : 'a -> 'b -> 'c optionvalA : 'a optionvalB : '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中定义的运算符。

chi*_*chi 5

在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)

并不复杂。