Chr*_*ner 7 haskell composition do-notation
对于简单的函数组合,是否有"do notation"语法糖?
(即(.) :: (b -> c) -> (a -> b) -> a -> c)
我希望能够存储一些成分的结果供以后使用(同时仍然继续链.
如果可能的话,我宁愿不使用RebindableSyntax扩展.
我正在寻找这样的东西:
composed :: [String] -> [String]
composed = do
fmap (++ "!!!")
maxLength <- maximum . fmap length
filter ((== maxLength) . length)
composed ["alice", "bob", "david"]
-- outputs: ["alice!!!", "david!!!"]
Run Code Online (Sandbox Code Playgroud)
我不确定这样的事情是否可能,因为早期函数的结果基本上必须通过"通过"maxLength的绑定,但我愿意听到任何其他类似的表达选项.基本上我需要收集信息,因为我通过合成以便以后使用它.
也许我可以用状态monad做这样的事情?
谢谢你的帮助!
编辑
这种事情有点起作用:
split :: (a -> b) -> (b -> a -> c) -> a -> c
split ab bac a = bac (ab a) a
composed :: [String] -> [String]
composed = do
fmap (++ "!!!")
split
(maximum . fmap length)
(\maxLength -> (filter ((== maxLength) . length)))
Run Code Online (Sandbox Code Playgroud)
实现类似目标的一种可能方式是箭头.基本上,在"存储插页式结果"中,您只是将信息流分解为组合链.这就是&&&(扇出)组合器的作用.
import Control.Arrow
composed = fmap (++ "!!!")
>>> ((. length) . (==) . maximum . fmap length &&& id)
>>> uncurry filter
Run Code Online (Sandbox Code Playgroud)
这绝对不是人类易于理解的代码.
状态monad似乎也允许相关的东西,但问题是状态类型是通过do块的monadic链固定的.这并不足以灵活地在整个构图链中获取不同类型的值.虽然肯定可以规避这一点(其中确实如此RebindableSyntax),但这也不是IMO的好主意.
正如leftaroundabout提到的,您可以使用Arrows来编写您的函数。但是, ghc Haskell 编译器有一个功能,即proc箭头的 - 表示法。它与众所周知的do- 表示法非常相似,但不幸的是,没有多少人意识到它。
使用proc-notation,你可以用下一种更可编辑和优雅的方式编写你想要的函数:
{-# LANGUAGE Arrows #-}
import Control.Arrow (returnA)
import Data.List (maximum)
composed :: [String] -> [String]
composed = proc l -> do
bangedL <- fmap (++"!!!") -< l
maxLen <- maximum . fmap length -< bangedL
returnA -< filter ((== maxLen) . length) bangedL
Run Code Online (Sandbox Code Playgroud)
这在ghci中按预期工作:
ghci> composed ["alice", "bob", "david"]
["alice!!!","david!!!"]
Run Code Online (Sandbox Code Playgroud)
如果您有兴趣,可以阅读一些带有精美图片的教程,以了解什么是箭头以及这个强大功能的工作原理,以便您可以更深入地了解它:
https://www.haskell.org/arrows/index.html
https://en.wikibooks.org/wiki/Haskell/Understanding_arrows