13

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。抽象データ型を作成せずにそれを行う方法はありますか?

4

2 に答える 2

17

標準的な方法は、値を作成する前に前提条件をチェックするスマートコンストラクターを使用し、使用する実際のコンストラクターをエクスポートしないことです。もちろん、あなたが言ったように、これは抽象データ型を作成しています。

スマートコンストラクタなしでこれを達成する唯一の方法は、本当に邪悪な型システムのハッカーです(そして、標準型を使用することはできませんDay)。

于 2012-04-15T09:55:58.380 に答える
15

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してスマート デストラクタにするにはf1、 、f2、およびf3をパラメータとして渡すだけです。

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と、基本的に、コンストラクターにアクセスする必要なく、型に対してパターン マッチを行うことができます。

maybe以前にまたは関数を使用しeitherたことがある場合は、スマート デストラクタを使用したことになりますが、その場合、コンストラクタは非表示にならないため、主に便利な関数として提供されます。

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

あなたの場合、スマートデストラクタの目的は、コンストラクタを非表示にしてコンストラクタを公開しないようにすることです。

于 2012-04-16T02:50:57.573 に答える