现在我有了这段代码,它获取一个列表,并对第一个元素执行某些操作,然后对其他每个元素执行一些操作。它返回一个转换后的元素列表。我遇到的问题是,我想要一个包含未转换元素和转换元素的列表。这就是我目前所拥有的:
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]
。
这里,a
和b
都是"刚性"类型,这意味着它们是由程序员显式指定的。GHC还注意到,在相关绑定中,y
的类型为a
。
所以,综上所述,您要求GHC评估表达式:
y : applyToEveryOther f xs
其中您已经指定y
的类型为a
,applyToEveryOther f xs
的类型为[b]
,而GHC拒绝这样做,因为Haskell中的列表不能混合两种不同的类型。
这是整个问题的关键。您想要将[a]
列表中的一些元素从a
转换为b
,但随后您想要返回a
s和b
s的混合列表。Haskell无法做到这一点!
函数工作的唯一方法是更改签名,使a
和b
为同一类型:
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