【问题标题】:dequeue function of a list in haskellhaskell中列表的出队功能
【发布时间】:2016-06-19 03:19:12
【问题描述】:

所以我有以下代码:

module Queue where

class Queue t 
  where
    enqueue :: t a -> a -> t a
    dequeue :: t a -> Maybe (t a, a)    

--和:

module DataQueue where

import Queue
data DQueue a = Empty | Enqueue a (DQueue a)
    deriving (Eq, Show, Read)

instance Queue DQueue
  where
    enqueue (Empty) s = Enqueue s (Empty)
    enqueue (Enqueue v ss) s = Enqueue s (Enqueue v ss)

    dequeue Empty = Nothing
    dequeue (Enqueue a (ss)) = Just(ss)

我将一个元素添加到列表(入队)中,效果很好。我还使用 dequeue 函数删除了列表中的一个元素。不知何故,我的 dequeue 函数的最后一行出现错误。它说:

“无法将预期类型 (DQueue a, a) 与实际类型 DQueue a 匹配”

我真的不明白如何解决这个问题。

【问题讨论】:

  • 通常,我们认为出队是从前面开始的,用像dequeue :: t a -> Maybe (a, t a)这样的类型签名来表示。不相关:多参数类型类和函数依赖提供了更好的表达方式。 class Queue el q | q -> el where { enqueue :: q -> el -> q; dequeue :: q -> Maybe (el, q) }。这允许单态(例如,未装箱)队列实例化类。

标签: haskell queue


【解决方案1】:

根据您的Queue 类,您的dequeue 函数必须在删除元素后返回队列。它可能应该被定义为

dequeue Empty = Nothing
dequeue (Enqueue a Empty) = Just (Empty, a)
dequeue (Enqueue a (ss)) = do
  (next, v) <- dequeue ss
  return (Enqueue a next, v)

此定义假定您在列表的开头将事物排队并从末尾将它们出队。

第三个 dequeue 匹配递归调用 dequeue 走到列表的末尾,在那里它获取列表值(参见第二个 dequeue 匹配),然后它再次构建 Enqueue 列表除了最后一个元素。

上面的例子利用了Maybe monad 和do 语法。如果这样更有意义的话,它可以表达如下:

dequeue (Enqueue a ss) =
  case dequeue ss of
    Just (next, v) -> Just (Enqueue a next, v)
    Nothing -> Nothing

【讨论】:

  • 通过这样做我得到以下错误:预期:Just (Enqueue 1 (Enqueue 2 (Enqueue 3 Empty)),4) 但得到:Just (Enqueue 2 (Enqueue 3 (Enqueue 4 Empty)) ),1)
  • 这听起来像是单元测试设置的另一个问题。你的预期正确吗?
  • 他们似乎是正确的。我有以下测试用例:dequeue sample1 ~?= (Just (Enqueue 1 $ Enqueue 2 $ Enqueue 3 Empty,4))
  • dequeue sample2 ~?= (Just (Enqueue "a" $ Enqueue "b" $ Enqueue "c" Empty,"d"))
  • 我更新了我的答案,因为我最初展示的是堆栈(推送/弹出)而不是队列的功能。
【解决方案2】:

查看出队的类型签名:

dequeue :: t a -> Maybe (t a, a)

...并将其与您在该行中实际返回的内容进行比较:

dequeue (Enqueue a (ss)) = Just(ss)

类型不匹配。现在可以修吗?


演练

dequeue 的类型是t a -&gt; Maybe (t a, a),这意味着它接受一个t a 类型的参数,并且应该返回一个Maybe (t a, a) 类型的值。

分解该类型,我们从最外面的“事物”开始:Maybe(“事物”被称为类型构造函数)。所以无论我们返回什么都必须是NothingJust &lt;some value&gt;。 进入Just 的是“在Maybe 内部”的内容,在本例中是(t a, a) 类型的值,它是t aa 的元组(对)。

现在看看你的代码是怎么说的:

dequeue (Enqueue a (ss)) = Just(ss)

返回值Just(ss)可以写成Just ss。让我们确定ss 的类型。由于我们定义:

data DQueue a = Empty | Enqueue a (DQueue a)
                                  ^^^^^^^^^^ <-- ss is of this type

ss 的类型因此为DQueue a。所以Just ss的类型是:Maybe (DQueue a)

现在,我们需要返回Maybe (t a, a)。在我们的Queue 类实例中,tDQueue,因此返回的类型更具体为:Maybe (DQueue a, a),但我们目前有Maybe (DQueue a)(记住ssDQueue a,所以Just ssMaybe (DQueue a))。

所以为了解决这个问题,我们应该返回Just (some pair),而不是Just ss。这对取决于我们希望dequeue 的行为方式。如果它就像一个弹出最后一个入队结果的堆栈,它可以是Just (ss, a)。否则,请参阅讨论如何实现它的其他答案。

【讨论】:

  • 我现在明白了。但很难解决它。我应该在 ss 旁边返回什么有用的东西?
  • @Vendetta,我添加了一些关于类型的更多解释。我看到另一个答案涉及队列实现
猜你喜欢
  • 1970-01-01
  • 2020-03-18
  • 1970-01-01
  • 2014-01-01
  • 1970-01-01
  • 2018-03-12
  • 2013-12-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多