在Haskell中的自定义列表上使用reverse

时间:2014-04-24 23:38:02

标签: haskell functional-programming

我做了一个名为Queue的自定义数据类型,并尝试将“整数”排列在“列表”的末尾。

data Queue = Ele Int Queue | Nil

-- [..] some other Functions

enqueue :: Int -> Queue -> Queue
enqueue x Nil = (Ele x Nil)
enqueue x (Ele _ restEles) = reverse (Ele x reverse restEles)

我收到错误:

  

“无法匹配预期类型Queue' with actual type [a0]'”。

我认为是,因为该函数不知道如何处理我的数据类型。我在这儿吗?我怎样才能解决这个问题?我是否必须编写自己的反向功能?如果你能帮助我,因为我还在学习Haskell并且不理解这一点:

reverse = foldl (flip (:)) []

3 个答案:

答案 0 :(得分:5)

是的,您已定义了一种新的数据类型。尽管它在结构上与列表类似,但Haskell会将其视为完全不同的。因此,您必须确实定义一个新的reverse函数,或者定义一个函数,将您的类型转换为标准列表并返回。

但对于enqueue,您不一定需要reverse。在enqueue的情况下,您可以在restEles上递归调用Ele,并将第一个元素放回到结果的前面。

这里是您完成直接递归定义的模式:

enqueue :: Int -> Queue -> Queue
enqueue x Nil                     = Ele x Nil
enqueue x (Ele firstEle restEles) = ...

对于......,你必须按照我上面所说的做法:以递归方式调用enqueue 元素并将第一个元素放回顶部。

答案 1 :(得分:2)

反向的类型是:

reverse :: [a] -> [a]

队列不是 [a] 。您需要实现自己的 reverseQueue 功能,该功能可以理解您的数据类型。

答案 2 :(得分:1)

至于问题的第二部分:

reverse :: [a] -> [a]
reverse = foldl (flip (:)) []

首先,确保您了解foldl。它是一个强大的高阶函数,这意味着它可以用来实现许多其他函数(summapfilter,当然还有reverse)。你可以阅读它here

现在,我们来看一个更简单的版本:

reverse :: [a] -> [a]
reverse xs = foldl (\ys y -> y:ys) [] xs

\ys y -> y:ys是一个非常简单的函数:它采用列表(ys)和值(y)并在列表(y:ys)之前插入值。所以我们的计划是:从空列表([])开始,将xs中的第一项插入其左侧,取结果并将第二项插入其左侧,依此类推。

让我们用一个简单的列表来模拟它 - [1,2,3]

  1. 我们从空列表开始 - []

  2. 将第一项(1)添加到左侧:[1]

  3. 将第二项(2)添加到[1]左侧:[2,1]

  4. 将第三项(3)添加到[2,1]左侧:[3,2,1]

  5. 我们已成功撤销[1,2,3]

    现在,flip是一个函数,它接受一个函数并“翻转”它的参数。因此,如果subtract a ba-b,则(flip subtract) a b等于subtract b a - b-a。因此,如果(:)是一个带有项y和列表ys并将该项添加到列表开头的函数,则flip (:)与翻转的功能相同参数 - 它需要一个列表和一个项目,就像我们的函数一样 - \ys y -> y:ys。所以我们可以替换它们中的两个:

    reverse :: [a] -> [a]
    reverse xs = foldl (flip (:)) [] xs
    

    现在我们用pointfree样式编写并从等式的两边消除xs并得到最终版本:

    reverse :: [a] -> [a]
    reverse = foldl (flip (:)) []