首页 文章

Haskell - 函数'length'不适用于自定义数据类型

提问于
浏览
2

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

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

这是餐厅员工的名单:(每个员工的姓名,地址,工资) .

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

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

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

如果我使用 type 而不是 data ,它为什么有效? (我可以't use the '键入' declaration in my code because it'关于'data'的练习的一部分)

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

3 回答

  • 1

    如果我使用类型而不是数据,为什么它可以工作?

    因为 type 是一个弱别名 . 在代码中,它等同于RHS上的类型 .

    另一方面, data (和 newtype ,或许更是如此)会创建一个"strong"别名,这意味着您需要先解压缩它:

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

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

  • 9

    函数 length 的类型为 [a] -> Int . 那就是它需要一个列表作为参数 . 但是你试图将 Restaurant 传递给它 .

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

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

    length 的类型是

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

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

    Nitpick

    你可以写

    type Foo a = Restaurant
    

    以便

    Foo a ~ Restaurant
    

    每个 a . 但是, Foo 将只是类型同义词/系列,而不是正确的第一类类型 . 只有使用 datanewtype 声明的真正类型,内置的 () ,列表和元组类型,奇怪的 -> 以及这些类型的应用程序才真正算在内 .

相关问题