7

我正在尝试创建一个名为 place 的新数据声明。

它看起来像这样:

data place = United States | France | England | Germany | Mexico | Canada

我希望然后使用一个名为 cap 的函数将这个位置带到它的首都,如下所示:

cap :: place -> String
cap a = case a of

            Spain           -> "Madrid"
            France          -> "Paris"
            England         -> "London"
            Germany         -> "Berlin"
            Mexico          -> "Mexico City"
            Canada          -> "Ottawa"
            _               -> undefined

但是,在最后一种情况下,我试图捕获数据声明中可能不存在的所有其他条目不起作用。例如,如果我capital Wales在 GHCI 中输入,我不会得到未定义的响应。相反,我得到一个不在范围内的错误。有人可以帮助我解决我的困惑,也许可以提供一种合法的方式来尝试捕捉其他案件吗?

4

3 回答 3

10

问题不在于你如何处理丢失的案例——你做得很好。问题是Wales构造函数根本不存在。因此,就像您尝试使用尚未定义的变量或函数一样,您会收到编译错误。您的cap函数甚至永远不会被调用,因此您无法对其进行任何更改都会影响此行为。您无法对使用不存在的构造函数的代码进行编译。

于 2013-02-12T23:12:21.243 回答
4

当您输入capital Wales时,范围内没有Wales。您不可能构造一个不存在的值。如果您已经涵盖了所有可能的情况,那么您不需要默认情况。

于 2013-02-12T23:10:17.447 回答
3

为了重复 sepp2k 和 singpolyma 的答案,这里的重点是 Haskell 的联合类型是详尽的。当你用n 个case定义联合类型时,你是在告诉 Haskell 这n 个case 是你的类型存在的唯一 case。正如 singpolyma 指出的那样,您已经告诉 Haskell 其他情况甚至不存在

这有好处也有坏处。详尽无遗意味着您和编译器可以保证您的函数正在处理它们将被给出的所有可能的输入。缺点是案例集在编译时是固定的。

这里最简单的选择是两部分:

  1. 使用“开放”类型(您可以在运行时为其创建任意多个不同实例)来表示国家和首都。字符串在这里是一个很好的选择。您可以在运行时构造无数种不同的字符串。但是您也可以使用带有字符串成员的记录类型。
  2. 使用键/值分配数据结构来表示国家和首都之间的关联。

所以你可以像这样代表国家和城市:

-- Since there are infinitely many different strings you could construct at runtime,
-- there are also infinitely many different Cities and Nations...
data City = City String deriving (Eq, Ord, Show)
data Nation = Nation String deriving (Eq, Ord, Show

最简单的键/值映射类型是[(k, v)],通常称为关联列表。它当然有一个 O(n) 的查找时间。更好的方法是使用Data.MapHaskell 平台附带的 .

于 2013-02-13T01:30:48.863 回答