现在我有了这个代码,它接受一个列表并对第一个元素执行某些操作,然后对其他元素执行某些操作。它返回转换元素的列表。我遇到的问题是我想要一个包含未转换元素和转换元素的列表。这就是我到目前为止所做的:
applyToEveryOther :: (a -> b) -> [a] -> [b]
applyToEveryOther _ [] = []
applyToEveryOther f [x] = [f x]
applyToEveryOther f (x:y:xs) = f x : y : applyToEveryOther f xs
它给我的错误说明函数的: y
部分存在问题
答案 0 :(得分:4)
当我尝试使用您的代码时,我会收到以下信息(确实有些冗长且令人困惑)错误消息:
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
和{{1}的混合列表}秒。哈斯克尔不能这样做!
您的功能可以使用的唯一方法是更改签名,以便b
和a
属于同一类型:
b
您的代码将正常运行。
你可以发现的另一种方式"正确的签名是将其遗漏并让Haskell推断出最普遍的签名。如果您将代码(没有显式签名)加载到GHCi中并询问类型,则会得到:
applyToEveryOther :: (a -> a) -> [a] -> [a]
这是此功能最常用的类型。
答案 1 :(得分:0)
如果我理解正确,你想要两者,原始值和转换值。
但是评估applyToEveryOther (+3) [0,1,2]
会返回[3,1,5]。如果您想要[0,3,1,4,2,5],请尝试
applyToEveryOther _ [] = []
applyToEveryOther f [x] = [x,f x]
applyToEveryOther f (x:xs) = x: f x : applyToEveryOther f xs