奇怪的不能匹配类型错误

时间:2015-03-30 12:43:54

标签: haskell types fold unfold

我有简单的一行功能:

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

1 个答案:

答案 0 :(得分:7)

首先,格式化代码:

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告诉您问题所在。根据{{​​1}}的类型,unfoldr应具有以下类型:

fun

,因为原始示例中b ~ Char a ~ Char fun :: Char -> Maybe (Char, Char) unfoldr

我通常喜欢验证小块,因此我们可以删除snd t的定义,只使用类型签名:

foo

GHC抱怨revRange :: (Char,Char) -> [Char] revRange t = unfoldr fun t fun:: Char -> Maybe (Char, Char) fun b = error "" 类型为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 "" 的定义。我们可以删除lambda并将fun作为b的正常参数:

fun

我们立即看到另一个明显的问题:fun:: Char -> Maybe (Char, Char) fun t b = if b == (pred (fst t)) then Nothing else Just (b, pred b) 需要两个参数,但签名说它只需要一个!

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

revRange

要解决您的评论,您想写一下

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 的签名中,我们需要unfoldrb ~ (Char,Char)。所以我们希望a ~ Char具有类型

fun2

我会将fun2 :: ((Char,Char) -> Maybe (Char, (Char, Char))) 的定义作为练习。作为提示,我建议采用惯例,该对的第一部分是常量并保持fun2