1

我有简单的一行功能:

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"

然后我想将展开器 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
4

1 回答 1

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)

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

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

接下来,添加类型签名,fun以便 GHC 告诉您问题所在。根据 的类型unfoldrfun应该有以下类型:

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有 type(Char, Char)fun期望 type 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 中的一个常数,我们可以通过部分应用funin来解决这个问题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

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

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

我将把定义fun2留作练习。作为提示,我建议采用该对的第一部分是恒定的并且成立的约定fst t

于 2015-03-30T12:53:43.317 回答