2012-04-15 30 views
13

如何将输入检查添加到Haskell数据构造函数中?假设我有Haskell数据构造函数中的输入检查

import Data.Time.Calendar 

data SchedulePeriod = SchedulePeriod { startDate :: Day 
    , endDate :: Day 
    , accrualStart :: Day 
    , accrualEnd :: Day 
    , resetDate :: Day 
    , paymentDate :: Day 
    , fraction :: Double } 
    deriving (Show) 

并且我想强加一个约束startDate < endDate。有没有办法做到这一点,而不创建一个抽象的数据类型?

+0

可能重复的[如何使限制类型](http://stackoverflow.com/questions/7978191/how-to-make-a-type-with-restrictions) – ehird 2012-04-15 09:57:43

回答

17

标准方法是使用smart constructor,它在创建值之前检查前提条件,并且不导出它使用的实际构造函数。正如你所说,当然这是创建一个抽象数据类型。

实现这一目标没有智能构造将是唯一的办法真正邪恶的类型系统的两轮牛车(你将无法使用标准Day型)。

+0

我可以在智能中使用命名参数构造函数? – 2012-04-15 10:56:09

+0

如果你的意思是模仿记录语法,那么不幸的不是。但是,您可以定义另一个记录以充当智能构造函数的输入。如果你的构造函数做了比验证输入更多的事情,那么这可能只值得重复。计算辅助字段)。 – ehird 2012-04-15 11:08:10

+3

@quant_dev如果你不想要抽象数据类型的原因是你可以对构造函数进行模式匹配,那么你可以执行智能构造函数和智能析构函数(类似于'maybe'和'either')。 – 2012-04-15 15:47:37

13

接受ehird的答案。我只是写这个,所以我可以解释我在评论中提到的智能析构函数,我不能在评论中适合解释。

比方说,你有类型:

data T x y z = A | B x | C y z 

ehird已经解释的构造,这是多么抽象掉,以提供“智能”的构造。就像你提到的,这需要隐藏构造函数,然后你不能用它们来模式匹配。但是,您可以使用“智能”析构函数来解决此问题,这相当于针对每个可能的构造函数进行模式匹配。

为了解释这一点,让我们先用我们怎么会写类型T的函数开始,如果构造函数暴露:

myFunction :: T x y z -> d 
myFunction t = case t of 
    A  -> f1 
    B x -> f2 x 
    C y z -> f3 y z 

我们从函数的类型签名知道类型的f1f2,和f3必须是:

f1 :: d 
f2 :: x -> d 
f3 :: y -> z -> d 

所以,如果我们要概括myFunction是一个聪明的析构函数,我们只是通过f1f2f3作为参数传递给它:

smartDestructor :: d -> (x -> d) -> (y -> z -> d) -> t -> d 
smartDestructor f1 f2 f3 t = case t of 
    A  -> f1 
    B x -> f2 x 
    C y z -> f3 y z 

因此,如果您导出smartDestructor,那么人们基本上可以模式匹配对你的类型,而无需访问构造函数。

如果你曾经使用过的maybeeither功能之前,那么你已经使用了智能的析构函数,虽然在这些情况下构造不会隐藏,所以他们主要是为提供方便的功能:

maybe :: b -> (a -> b) -> Maybe a -> b 
maybe f1 f2 m = case m of 
    Nothing -> f1 
    Just a -> f2 x 

either :: (a -> c) -> (b -> c) -> Either a b -> c 
either f1 f2 e = case e of 
    Left a -> f1 a 
    Right b -> f2 b 

就你而言,智能析构函数的目的就是让你可以隐藏构造函数而不会暴露构造函数。

+0

谢谢,非常有启发性。我希望我可以接受两个答案... – 2012-04-16 09:34:21

+3

@quant_dev我刚才了解到,“智能析构函数”有一个更好的名称。它被称为“教会编码”数据类型,它指的是任何数据类型都可以表示为一个函数,而这种函数编码被称为“教会编码”。对于一个非常好的解释,看看这个链接:http://web.archiveorange.com/archive/v/nDNOvgzSRV6TNq8KhCgZ – 2012-04-28 00:16:28

+0

谢谢,我会读。 – 2012-04-28 10:08:45