【问题标题】:Haskell - Function 'length' doesn't work with custom data typeHaskell - 函数“长度”不适用于自定义数据类型
【发布时间】:2015-10-29 03:10:36
【问题描述】:

我是 Haskell 新手,我需要定义这种数据类型:

data Restaurant = Restaurant [(String, String, Int)] deriving (Eq,Show)

这是餐厅员工的列表:每个员工的(姓名、地址、工资)。

现在,我正在尝试定义这个 numberOfEmployees 函数:

numberOfEmployees :: Restaurant -> Int
numberOfEmployees rest = length rest

但是我得到这个编译错误: 无法将预期类型“t2 a0”与实际类型“Restaurant”匹配

为什么我使用 type 而不是 data 会起作用? (我不能在我的代码中使用“类型”声明,因为它是关于“数据”的练习的一部分)

type Restaurant = [(String, String, Int)]

【问题讨论】:

  • 旁注:每次你说“我不能那样做”时,都应该在这里说明原因。
  • 你是对的,对不起。我刚刚更正了。

标签: haskell


【解决方案1】:

如果我使用类型而不是数据,为什么它会起作用?

因为type 是一个弱别名。在代码中,它相当于RHS上的类型。

另一方面,data(和newtype,也许更是如此)创建了一个“强”别名,这意味着您需要先解压缩它:

numberOfEmployees :: Restaurant -> Int
numberOfEmployees (Restaurant rest) = length rest

如果您想限制对数据的操作,这一点尤其重要。如果您的内部模块不导出构造函数,则用户只能使用您的智能构造函数和其他运算符,并且无法直接访问或修改包装的数据(实际上使其不透明)。 p>

【讨论】:

  • 谢谢你!我认为在这种情况下,编译器可以推断出我的数据“内部”的类型。
  • 技术上可以,但故意不行。 data 暗示用户将手动指定所有行为。
  • 除此之外,我很确定你可以derive Foldable
【解决方案2】:

函数length 的类型为[a] -> Int。也就是说,它需要一个列表作为参数。但是您正在尝试将Restaurant 传递给它。

您应该使用模式匹配来获取列表并将其传递给length

numberOfEmployees :: Restaurant -> Int
numberOfEmployees (Restaurant a) = length a

【讨论】:

  • 那不再是它的类型了,如果是的话,错误信息会有所不同。
  • length 现在有类型 Foldable f => f a -> Int
  • @dfeuer 然而,命题“长度具有类型 [a] -> Int”仍然正确。为了验证,编译myLength :: [a] -> Int; myLength = length
  • @Ingo,这是真的。然而,学习 Haskell 的一个关键部分是掌握解释类型错误的窍门。在length :: [a] -> Int 的假设下,OP 得到的类型错误毫无意义。
  • @dfeuer ...我想这是一些人反对 FTP 提案的原因之一。
【解决方案3】:

length 的类型是

length :: Foldable t => t a -> Int

但是没有类型ta 使得Restaurant 类型等于t a。正如其他人所解释的那样,您需要拉出列表并找到列表的长度 - Restaurant 永远不会有 length

吹毛求疵

你可以写

type Foo a = Restaurant

这样

Foo a ~ Restaurant

对于每个a。但是,Foo 将只是一个类型同义词/系列,而不是一个适当的一流类型。只有使用 datanewtype 声明的真正类型、内置的 ()、列表和元组类型、奇怪的 -> 以及这些类型的应用,才真正重要。

【讨论】:

    猜你喜欢
    • 2011-12-20
    • 2014-08-05
    • 1970-01-01
    • 2020-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多