简体   繁体   English

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

[英]A Haskell List Involving Recursion and High Order Functions

Now I have this code that takes a list and does something to the first element and then to every other one. 现在,我有了这段代码,它获取一个列表,并对第一个元素然后对其他每个元素进行处理。 And it returns a list of the transformed elements. 并返回已转换元素的列表。 The problem I am having is that I want to have a list that contains the untransformed and the transformed elements. 我遇到的问题是我想拥有一个包含未转换和已转换元素的列表。 This is what I have so far: 这是我到目前为止的内容:

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

The error it is giving me says there is a problem with the : y part of the function 它给我的错误表明函数的: y部分存在问题

When I try your code, I get the following (admittedly somewhat lengthy and confusing) error message: 当我尝试您的代码时,出现以下(当然有些冗长和令人困惑的)错误消息:

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)

However, it's worth trying to figure out what GHC is saying here. 但是,值得尝试弄清楚GHC在这里所说的话。 As per the second bullet point, GHC was processing the subexpression y : applyToEveryOther f xs , and specifically looking at the second argument to the : operator in that expression (namely applyToEveryOther f xs . It expected that expression to have type [a] , but the actual type of the expression was type [b] . 根据第二个要点,GHC正在处理子表达式y : applyToEveryOther f xs ,并专门查看该表达式中:运算符的第二个参数(即applyToEveryOther f xs 。它希望该表达式的类型为[a] ,但是表达式的实际类型是[b]类型。

Here, a and b are both "rigid" types, meaning simply that they were specified explicitly by the programmer. 在此, ab都是“刚性”类型,仅表示它们是由程序员明确指定的。 GHC also notes, in the relevant bindings, that y had type a . GHC在相关绑定中还指出y类型为a

So, to sum up, you asked GHC to evaluate the expression: 因此,总而言之,您要求GHC评估表达式:

y : applyToEveryOther f xs

where you already specified that y had type a and applyToEveryOther f xs had type [b] , and GHC refused to do this because lists in Haskell can't mix two different types. 您已经指定y类型为aapplyToEveryOther f xs类型为[b] ,而GHC拒绝这样做,因为Haskell中的列表无法混合使用两种不同的类型。

And that's kind of the key to the whole problem. 这就是解决整个问题的关键。 You want to transform some of the elements of your [a] list from a to b , but then you want to return a mixed list of a s and b s. 你想改变你的一些的元素[a]列表从ab ,但你要返回的混合列表a S和b秒。 Haskell can't do that! Haskell无法做到这一点!

The only way your function can work is if you change the signature so that a and b are the same type: 函数的唯一工作方式是更改签名,以使ab为同一类型:

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

and your code will work fine. 并且您的代码可以正常工作。

Another way you could "discover" the correct signature is to leave it out and have Haskell infer the most general possible signature. 您可以“发现”正确签名的另一种方法是将其遗漏,让Haskell推断出最通用的签名。 If you load the code (without the explicit signature) into GHCi and ask for the type, you get: 如果将代码(没有显式签名)加载到GHCi中并要求输入类型,则会得到:

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

which is the most general possible type for this function. 这是此功能最通用的类​​型。

If I understood correctly you wanted both, the original and transformed values. 如果我理解正确,那么您既需要原始值又需要转换后的值。

However evaluating applyToEveryOther (+3) [0,1,2] returns [3,1,5]. 但是,评估applyToEveryOther (+3) [0,1,2]返回[3,1,5]。 If you want [0,3,1,4,2,5] as a result, try 如果您想要[0,3,1,4,2,5]结果,请尝试

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM