我试图了解 Haskell 列表理解在模式匹配方面是如何“在幕后”工作的。以下 ghci 输出说明了我的观点:
Prelude> let myList = [Just 1, Just 2, Nothing, Just 3]
Prelude> let xs = [x | Just x <- myList]
Prelude> xs
[1,2,3]
Prelude>
如您所见,它能够跳过“Nothing”并仅选择“Just”值。我知道 List 是一个单子,定义为(来自 Real World Haskell,第 14 章):
instance Monad [] where
return x = [x]
xs >>= f = concat (map f xs)
xs >> f = concat (map (\_ -> f) xs)
fail _ = []
因此,列表推导基本上为列表推导中选择的每个元素构建一个单例列表并将它们连接起来。如果模式匹配在某个步骤失败,则使用“失败”函数的结果。换句话说,“Just x”模式不匹配,因此 [] 用作占位符,直到调用 'concat'。这就解释了为什么“无”似乎被跳过了。
我不明白的是,Haskell 怎么知道调用“失败”函数?它是“编译器魔法”,还是您可以在 Haskell 中自己编写的功能?是否可以编写以下“选择”函数以与列表理解相同的方式工作?
select :: (a -> b) -> [a] -> [b]
select (Just x -> x) myList -- how to prevent the lambda from raising an error?
[1,2,3]