奇怪的无法匹配类型错误

Weird couldn't match type error

我有简单的一行函数:

revRange :: (Char,Char) -> [Char]
revRange t = unfoldr (\b -> if b == (pred (fst t)) then Nothing else Just (b, pred b)) (snd t)

效果不错:

*Main Data.List> revRange ('a', 'f')
"fedcba"

然后我想将 unfoldr lambda 提取为唯一函数:

revRange :: (Char,Char) -> [Char]
revRange t = unfoldr fun t
fun t = (\b -> if b == (pred (fst t)) then Nothing else Just (b, pred b)) (snd t)

现在,我有一个奇怪的错误:

Couldn't match type `Char' with `(Char, Char)'
Expected type: (Char, Char) -> Maybe (Char, (Char, Char))
  Actual type: (Char, Char) -> Maybe (Char, Char)
In the first argument of `unfoldr', namely `fun'
In the expression: unfoldr fun t

首先,格式化您的代码:

revRange :: (Char,Char) -> [Char]
revRange t = unfoldr fun t
fun t = (\b -> if b == (pred (fst t)) 
               then Nothing 
               else Just (b, pred b)) (snd t)

接下来,使用 Hoogle 仔细检查 unfoldr 的类型:

unfoldr :: (b -> Maybe (a, b)) -> b -> [a]

接下来,将类型签名添加到fun,这样GHC 就会告诉您问题出在哪里。根据unfoldr的类型,fun的类型应该是:

b ~ Char
a ~ Char

fun :: Char -> Maybe (Char, Char)

因为在原始示例中您是 unfoldr snd t

平时喜欢验证小块,所以我们可以去掉foo的定义,直接使用类型签名:

revRange :: (Char,Char) -> [Char]
revRange t = unfoldr fun t

fun:: Char -> Maybe (Char, Char)
fun b = error ""

GHC 抱怨 t 的类型为 (Char, Char)fun 需要类型 Char。您调用了 unfoldr fun t 而不是原始示例中的 unfoldr fun (snd t) 。将该位从 fun 移动到 revRange:

revRange :: (Char,Char) -> [Char]
revRange t = unfoldr fun (snd t)

fun:: Char -> Maybe (Char, Char)
fun b = error ""

接下来,再次添加fun的定义。我们可以删除 lambda 并将 b 作为 fun:

的普通参数
fun:: Char -> Maybe (Char, Char)
fun t b = if b == (pred (fst t)) 
          then Nothing 
          else Just (b, pred b)

我们立即看到另一个明显的问题:fun 接受 两个 个参数,但签名说它应该只接受一个!

由于t在原来的lambda中是一个常量,我们可以通过在revRange中部分应用fun来解决这个问题,所以最终答案是:

revRange :: (Char,Char) -> [Char]
revRange t = unfoldr (fun t) (snd t)

fun:: (Char, Char) -> Char -> Maybe (Char, Char)
fun t b = if b == (pred (fst t)) 
          then Nothing 
          else Just (b, pred b)

为了解决你的评论,你想写

revRange :: (Char,Char) -> [Char]
revRange = unfoldr fun2

使用与上述相同的方法,在 unfoldr 的签名中我们需要 b ~ (Char,Char)a ~ Char。所以我们希望 fun2 具有类型

fun2 :: ((Char,Char) -> Maybe (Char, (Char, Char)))

我将 fun2 的定义留作练习。作为提示,我建议采用该对的第一部分是常量并保持 fst t.

的约定