一个包含递归和高阶函数的Haskell列表



现在我有了这段代码,它获取一个列表,并对第一个元素执行某些操作,然后对其他每个元素执行一些操作。它返回一个转换后的元素列表。我遇到的问题是,我想要一个包含未转换元素和转换元素的列表。这就是我目前所拥有的:

applyToEveryOther :: (a -> b) -> [a] -> [b]
applyToEveryOther _ [] = []
applyToEveryOther f [x] = [f x]
applyToEveryOther f (x:y:xs) = f x : y : applyToEveryOther f xs

它给我的错误说函数的: y部分有问题

当我尝试您的代码时,我会收到以下错误消息(诚然有些冗长和混乱):

EveryOther.hs:4:42: error:
• Couldn't match type ‘b’ with ‘a’
‘b’ is a rigid type variable bound by
the type signature for:
applyToEveryOther :: forall a b. (a -> b) -> [a] -> [b]
at EveryOther.hs:1:22
‘a’ is a rigid type variable bound by
the type signature for:
applyToEveryOther :: forall a b. (a -> b) -> [a] -> [b]
at EveryOther.hs:1:22
Expected type: [a]
Actual type: [b]
• In the second argument of ‘(:)’, namely ‘applyToEveryOther f xs’
In the second argument of ‘(:)’, namely
‘y : applyToEveryOther f xs’
In the expression: f x : y : applyToEveryOther f xs
• Relevant bindings include
xs :: [a] (bound at EveryOther.hs:4:26)
y :: a (bound at EveryOther.hs:4:24)
x :: a (bound at EveryOther.hs:4:22)
f :: a -> b (bound at EveryOther.hs:4:19)
applyToEveryOther :: (a -> b) -> [a] -> [b]
(bound at EveryOther.hs:2:1)

然而,值得试着弄清楚GHC在这里说了什么。根据第二个要点,GHC正在处理子表达式y : applyToEveryOther f xs,特别是查看该表达式中:运算符的第二个参数(即applyToEveryOther f xs)。它期望该表达式的类型为[a],但该表达式的实际类型是[b]

这里,ab都是"刚性"类型,这意味着它们是由程序员显式指定的。GHC还注意到,在相关绑定中,y的类型为a

所以,综上所述,您要求GHC评估表达式:

y : applyToEveryOther f xs

其中您已经指定y的类型为aapplyToEveryOther f xs的类型为[b],而GHC拒绝这样做,因为Haskell中的列表不能混合两种不同的类型。

这是整个问题的关键。您想要将[a]列表中的一些元素从a转换为b,但随后您想要返回as和bs的混合列表。Haskell无法做到这一点!

函数工作的唯一方法是更改签名,使ab为同一类型:

applyToEveryOther :: (a -> a) -> [a] -> [a]

并且您的代码将正常工作。

另一种"发现"正确签名的方法是将其排除在外,让Haskell推断出最通用的签名。如果你将代码(没有明确的签名)加载到GHCi中并要求输入类型,你会得到:

> :t applyToEveryOther
applyToEveryOther :: (a -> a) -> [a] -> [a]
>

这是该函数的最通用的可能类型。

如果我理解正确,您需要原始值和转换值。

但是,评估applyToEveryOther (+3) [0,1,2]会返回[3,1,5]。如果您想要[0,3,14,2,5]作为结果,请尝试

applyToEveryOther _ [] = []
applyToEveryOther f [x] = [x,f x]
applyToEveryOther f (x:xs) = x: f x : applyToEveryOther f xs

最新更新