也许作为Haskell数据类型

时间:2018-04-08 12:31:58

标签: haskell types maybe

假设我们想为某人的健康状况建模。该人可能生病并且有FluColdAllergyHealthy。我们可以通过多种方式在Haskell中定义它,其中两种方法是:

data Condition = Flu | Cold | Allergy | Healthy

data Condition = Flu | Cold | Allergy
data Sickness  = Sickness (Maybe Condition)

这类似于定义Tree结构,因为Tree元素可以是NodeTree s或Empty

data Tree a = Node (Tree a) (Tree a) | Empty

或者Tree也可以使用Maybe定义:

data Node a = Node (Tree a) (Tree a)
data Tree a = Tree (Maybe (Node a))

每种选择都有其优点和缺点。如果不使用Maybe,我们会在单个数据声明中捕获TreeHealth的所有可能值,因此范围非常明确。另一方面,如果我们使用Mayb e,那么我们捕获数据模型中可能存在或可能不存在某些内容的本质,并避免创建像Empty或{{}这样的无定义数据类型1}}并且只需使用Healthy来模拟缺席。这稍微简化了模型,但数据类型的声明不再包含在单个代码中。

这两种方法的其他优点和缺点是什么?

2 个答案:

答案 0 :(得分:2)

显然,正如有些人所指出的,任何给出的答案在某种程度上都是主观的。然而,代码不仅仅是使计算机执行计算的一种方式 - 它也是一种通信媒介。

您可以更清楚地向将来阅读代码的人传达您的意图,您就能更好地解决这个问题。从the Zen of Python

获取提示
  

显式优于隐式

这种启发式技术在许多不同的编程语言和场景中都很有用。一个必然结果是在面向对象的编程中,应该favour explicit domain objects over primitive obsession

我倾向于在OP这样的情况下应用类似的经验法则,如果他们更好地传达意图,则倾向于明确命名类型。

答案 1 :(得分:1)

我认为决定的很大一部分取决于你认为Healthy作为条件的有意义的。如果答案“不是很多”,那么最好使用Maybe编码(参见here)来讨论更明确的案例。顺便说一句,如果疾病不是相互排斥的,并且还有其他因素导致疾病,我们将不得不采用一种不同的编码:

import qualified Data.Set as Set
import Data.Set (Set)

data Sickness = Flu | Cold | Allergy
    deriving (Eq, Ord)

data Alertness = Sleepy | Distracted | Caffeinated
    deriving (Eq, Ord)

data Condition = Condition (Set Sickness) (Set Alertness)

我觉得在Healthy作为一种单独的条件的情况下,这种情况会明显减少。

回到原来的表述,值得一提的是有一个中间的第三个选项:滚动你自己的专门的,特定领域的Maybe(参见this question):

data Sickness = Flu | Cold | Allergy

data Condition = Healthy | Sick Sickness

通过这样做,您将错过Maybe - 处理工具,如果您想使用它们,您可能必须自己提供一些实例和功能(尽管这可能不是问题,取决于你打算如何使用Condition)。