只是为了一些不会咬人的品种和一些额外的信息......
在 Haskell 中 the list type is an instance of Monad class。所以像filter 这样的列表操作可以简单地通过一元绑定操作符来实现。
*Main> [(1,2.3),(3,21.2),(5,17.1),(4,24.4)] >>= \t -> if snd t < 25 && snd t > 18.5 then [t] else []
[(3,21.2),(4,24.4)]
Monad 就是按顺序处理包含的数据。在列表单子中,包含的数据是列表本身的值。因此,绑定运算符可以非常方便地以顺序方式访问一元值(元组列表)的包含值(元组)。
(>>=) :: Monad m => m a -> (a -> m b) -> m b
monadic 绑定操作符的类型签名声明它接受一个 monad 类型值 m a 作为第一个参数(这里是元组列表)和一个函数作为第二个参数,它接受一个纯值并返回一个 monadic 值(接受一个元组并返回一个列表中的一个元组,或者在这种情况下返回一个空列表)。
\t -> if snd t < 25 && snd t > 18.5 then [t] else []
了解如何以及为什么将列表项一一应用于所提供的函数至关重要。整个列表是一个单子值,绑定运算符访问的包含的值被传递给提供的a -> m b(取一个纯值并返回单子值)类型函数。因此,应用于此函数的所有列表项都成为一元值([t] 如果条件满足或[] 如果它失败),然后由绑定运算符连接形成一个单子返回值(在这种情况下是一个列表满足在 lambda 函数中实现的条件的元组)。
这个单子操作也可以用do 表示法实现
do
t <- [(1,2.3),(3,21.2),(5,17.1),(4,24.4)]
if snd t < 25 && snd t > 18.5 then return t else []
[(3,21.2),(4,24.4)]
当然,这非常类似于列表推导式,它实际上是一元列表操作的语法糖。因此,让我们最后一次使用列表推导来实现它。
*Main> [t | t <- [(1,2.3),(3,21.2),(5,17.1),(4,24.4)], snd t < 25 && snd t > 18.5]
[(3,21.2),(4,24.4)]