あなたが達成したいことは本当に明確ではありません。どこでも使用できる型が必要なように聞こえますStringが、同時に、文字列が取り得る可能な値のサブセットにしかなり得ません。しかし..それは本当にどういう意味ですか?
たとえば、これらの機能の両方を許可する必要がありますか?
reverseCar :: Car -> Car
reverseCar = reverse
idCar :: Car -> Car
idCar = map id
調べてみると、 がreverseCar実際には ではなくなった出力値を生成することがわかりますCar。しかしidChar、実際には何も変更されないため、出力は依然としてCar. しかし、それを自動的にチェックできるコンパイラを構築することは不可能です。
したがって、どこでも使用できる型を持つことはできずString、同時に、機能するStringが非Car値になる関数を適用できなくなります。
以下を除いて:
data Char = Ford | Chevy
あなたのオプションは、タイプエイリアスといくつかのヘルパー関数を使用することです:
type Car = String
ford :: Car
ford = "ford"
chevy :: Car
chevy = "chevy"
これにより、タイプミスを防ぐことができ、 a を使用できる場所ならどこでも afrodを使用できるようになります。ただし、無効な型を作成するような関数も適用できることを意味します。CarStringreverseCar
さらに一歩進んで、newtype ラッパーを使用することもできます。
newtype Car = Car { carToString :: String }
ford :: Car
ford = Car "ford"
chevy :: Char
chevy = Car "chevy"
次に、 a を安全に使用できる一連の信頼できる関数を定義し、Carそれらの関数のみをエクスポートしますが、Carデータ コンストラクターはエクスポートしません。reverseそれは、人々が のような関数を直接適用することを妨げCarます。代わりに、安全な関数carToStringだけに制限したくないことをコンパイルに伝えるために使用する必要があります。Car
これもおそらくあなたが望むものではありません。しかし、自分が何を望んでいるのかを正確に説明しようとすればするほど、自分が望んでいることが一貫していない、または不可能であることに気付くでしょう。
不可能とは、'Haskell では不可能' という意味ではなく、'停止問題を不可能に解決する必要がある' という意味です。
あなたが与えた例はInteger、リテラル3.567を許可しないことです。それはさまざまな問題を混同しています。データ型自体にはInteger3.567 を表現する方法がありません。次のようになります。
data Integer = I Int32 | J [Digit]
つまり、マシンの int で表現できる小さな整数か、数字のリストです。したがって、型自体は小数点の使用を明示的に禁止しています。よく似てる
data Car = Ford | Chevy
「リンゴ」を表現するのを防ぎます。
ソースコードの数値リテラルを値に変換するという問題もありIntegerます。(3.567 :: Integer) と書くと、これは本質的に省略形であり、次のように展開されます。
(fromRational (3567 % 100)) :: Integer
次のようなエラーが表示されます。
No instance for (Fractional Integer)
arising from the literal `3.567'
Integerしかし..それは、リテラル値をorのような型に変換するプロセスですDouble。IntegerとDoubleがサブタイプである一般的な数値型はありません。
quasi-quoter を使用して同様のことを行うことCarができるため、次のように記述できます。
myCar :: Car
myCar = [car| ford |]
そして、それは受け入れられますが、これは拒否されます:
notMyCar :: Car
notMyCar = [car| apple |]
しかし今、私たちは本当に深いところから外れてしまい、あなたが望んでいたものに近づくことはできませんでした..あなたが何を望んでいるのかはまだかなり不明です