首先,格式化您的代码:
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 告诉您问题所在。根据 的类型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
有 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 中的一个常数,我们可以通过部分应用fun
in来解决这个问题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
。