haskell - 如何定义一个允许统一访问 Haskell 中不同记录的类?

标签 haskell

我有两条记录,它们都有一个要提取以供显示的字段。如何安排事物以便可以使用相同的功能对其进行操作?由于它们具有不同的字段(在本例中为 firstNamebuildingName )作为它们的名称字段,因此它们每个都需要一些“适配器”代码来映射 firstNamename .这是我到目前为止所拥有的:

class Nameable a where
  name :: a -> String

data Human = Human {
  firstName :: String
}

data Building = Building {
  buildingName :: String
}

instance Nameable Human where
  name x = firstName x

instance Nameable Building where
  -- I think the x is redundant here, i.e the following should work:
  -- name = buildingName
  name x = buildingName x

main :: IO ()
main = do
  putStr $ show (map name items)
  where
    items :: (Nameable a) => [a]
    items = [ Human{firstName = "Don"}
            -- Ideally I want the next line in the array too, but that gives an 
            -- obvious type error at the moment.
            --, Building{buildingName = "Empire State"}
            ]

这不会编译:
TypeTest.hs:23:14:
    Couldn't match expected type `a' against inferred type `Human'
      `a' is a rigid type variable bound by
          the type signature for `items' at TypeTest.hs:22:23
    In the expression: Human {firstName = "Don"}
    In the expression: [Human {firstName = "Don"}]
    In the definition of `items': items = [Human {firstName = "Don"}]

我会期待 instance Nameable Human部分将使这项工作。有人可以解释我做错了什么,以及我想要工作的“概念”是什么,因为我不知道要搜索什么。

This question感觉相似,但我无法弄清楚与我的问题的联系。

最佳答案

考虑 items 的类型:

items :: (Nameable a) => [a] 

就是说对于任何 Nameable类型,items会给我一个该类型的列表。它没有说items是一个可能包含不同 Nameable 的列表类型,如您所想。你想要像 items :: [exists a. Nameable a => a] 这样的东西, 除了你需要引入一个包装器类型并使用 forall反而。 (见:Existential type)
{-# LANGUAGE ExistentialQuantification #-} 

data SomeNameable = forall a. Nameable a => SomeNameable a 

[...]

items :: [SomeNameable]
items = [ SomeNameable $ Human {firstName = "Don"},
          SomeNameable $ Building {buildingName = "Empire State"} ]
SomeNameable 的数据构造函数中的量词基本上允许它忘记关于哪个 a 的所有内容使用,除了它是Nameable .因此,您只能使用 Nameable 中的函数。关于元素的类。

为了更好地使用它,您可以为包装器创建一个实例:
instance Nameable (SomeNameable a) where
    name (SomeNameable x) = name x

现在你可以像这样使用它:
Main> map name items
["Don", "Empire State"]

关于haskell - 如何定义一个允许统一访问 Haskell 中不同记录的类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6677834/

相关文章:

Haskell 和 Rank-N 多态性

Haskell - 函数不适用于无限列表

haskell - Haskell 中的 do-blocks 中简洁的 if-then-else 表示法

windows - 无法让 Freeglut 在 Windows 上与 Haskell 一起工作

具有模式匹配的 Haskell `where`

haskell - 为什么下面的 Haskell 代码会挂起?

haskell - 中缀模式匹配

haskell - Helm 中的示例是什么?

haskell 优雅的方式从无限的数字列表中过滤(减少)重复序列

haskell - 如何将文字 1 作为 Maybe Integer 返回?