haskell - 在 haskell 中为 monad 创建过滤函数

标签 haskell monads

假设我们有一个过滤函数。

filterM::Monad m => (a -> m Bool) -> [a] -> m [a]

假设我们的 a -> m Bool 函数如下:

p :: Integer -> Maybe Bool
p n | n > 0 = Just True
    | n < 0 = Just False
    | otherwise = Nothing

在示例中,m 是 Maybe。

我想创建 filterM 函数,以便:

filterM p [2,−4,1] = Just [2,1]

filterM p [2,0,−4,1] = Nothing

本质上这个filterM是过滤器,但是针对monad。

这是我的实现。它不起作用,我有几个问题。

filterM p [] = pure []
filterM p (x : xs) | p x == Just True = x : (filterM p xs)
                   | p x == Just False = filterM p xs
                   | otherwise = Nothing

首先,为什么它不起作用。它说无法将类型 m 与 Maybe m 是刚性类型变量匹配。

  Expected type: m Bool
  Actual type: Maybe Bool

在我的函数中,我将“也许”硬编码为 m,但如何使其更通用?

我会使用 do 表示法,但它似乎不是最好的选择,因为存在递归。

最佳答案

有两个问题。首先是您已经给出了类型签名:

filterM :: Monad m => (a -> m Bool) -> [a] -> m [a]

然后定义 filterM ,其中 m 专门用于 Maybe (因为您使用 JustNothing 在你的定义中)。当 Haskell 推断出 m 必须是 Maybe 时,这会导致错误。类型 m 是“刚性”的,因为它是由您在类型签名中提供的,并且刚性类型必须保持通用;如果它们的多态性低于指定值,则会发生冲突。您可以通过编写以下内容来生成类似的错误消息:

badId :: a -> Int
badId x = x

显然,aInt,因此刚性(程序员指定的)类型 a 被确定为匹配 Int 在类型检查期间。

但是,即使您修复了类型签名:

filterM :: (a -> Maybe Bool) -> [a] -> Maybe [a]
filterM p [] = pure []
filterM p (x : xs) | p x == Just True = x : (filterM p xs)
                   | p x == Just False = filterM p xs
                   | otherwise = Nothing

您仍然会收到错误消息。您在代码中混淆了单元操作和值。表达式中:

x : filterM p xs

您正在将运算符 (:)::b -> [b] -> [b] 应用于类型 aMaybe [a ],因此它不会进行类型检查(“无法将预期类型 也许 [a] 与实际类型 [a] 匹配。”)

您需要将 x : filterM p xs 替换为以下内容:

case filterM p xs of
    Nothing -> Nothing
    Just xs' -> Just (x : xs')

关于haskell - 在 haskell 中为 monad 创建过滤函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55562988/

相关文章:

haskell - 使用状态单子(monad)隐藏显式状态

unit-testing - 模拟 IO 操作 : getArgs and putStrLn

haskell - Stack/Docker/IHaskell 奇怪的行为

haskell - Scheme中没有显式突变的向后延续的最简单示例

Haskell - 过滤器、柯里化(Currying)

haskell - 在单个输入上从多个正确的解析器中进行选择

haskell - 也许是 monad 构建

java - 为 kotlin 尝试 monad

haskell - 包含函数的数据类型的仿函数实例

haskell - 我可以将模式传递给函数吗?