第一个1-Haskell-a-Day 练习让我困惑到无法回头。目标是过滤掉列表中的元素,除非它等于以下元素。例如
> filterByPair [1, 2, 2, 2, 3, 3, 4]
[2,2,3]
Run Code Online (Sandbox Code Playgroud)
(我试图制作两个偏移量列表,将它们压缩成元组并删除两次没有相同数字的元组,例如 [(2,2),(2,2),(3,3)],等)但令人兴奋的简单解决方案使用=<<
绑定运算符:
filterByPair :: Eq a => [a] -> [a]
filterByPair = (init =<<) . group
Run Code Online (Sandbox Code Playgroud)
我很难弄清楚那个运算符。当我尝试使用 ghci 时,我没有得到相同的结果:
> init =<< [2,3,4]
No instance for (Num [b0]) arising from the literal `2'
Run Code Online (Sandbox Code Playgroud)
我发现在 ghci 中我可以使用,比如说,replicate
与=<<
. 它似乎将列表的每个元素都输入到函数中:
> replicate 2 =<< [2,3,4]
[2,2,3,3,4,4]
Run Code Online (Sandbox Code Playgroud)
所以第一次复飞相当于:
> replicate 2 2
[2,2]
Run Code Online (Sandbox Code Playgroud)
它以某种方式知道将列表放在 的第二个参数中replicate
,而不是第一个参数中,并将它们全部输出到一个大列表中而不是单独的列表中,就像fmap
这样:
> fmap (replicate 2) [2,3,4]
[[2,2],[3,3],[4,4]]
Run Code Online (Sandbox Code Playgroud)
我读过绑定运算符是由正在使用的 monad 定义的。这是一个 monad 函数,不是吗?monad 在哪里filterByPair
?它与Eq
签名中的类型类有关吗?
同样,如果我=<<
在 ghci 中单独使用,那里使用的是什么 monad?
首先,filterPairs
为了清楚起见,重写为有针对性的形式:
filterPairs xs = group xs >>= init
Run Code Online (Sandbox Code Playgroud)
我们将能够很好地了解仅从类型中发生了什么。
xs :: Eq a => [a]
group :: Eq a => [a] -> [[a]]
init :: [a] -> [a]
(>>=) :: Monad m => m a -> (a -> m b) -> m b
Run Code Online (Sandbox Code Playgroud)
第一个参数(>>=)
是group xs :: [[s]]
,所以如果我们替换m ~ []
and a ~ [s]
in(>>=)
我们会得到
(>>=) :: [[a]] -> ([a] -> [s]) -> [s]
Run Code Online (Sandbox Code Playgroud)
所以我们使用这里的Monad
实例[]
,它相当于concatMap
(检查类型!)。现在我们可以filterPairs
再次重写
filterPairs xs = concatMap init (group xs)
Run Code Online (Sandbox Code Playgroud)
现在,如果你弄清楚如何concatMap
,init
和group
工作,你应该能够人物如何原来的filterPairs
作品。