あなたが達成したいことは本当に明確ではありません。どこでも使用できる型が必要なように聞こえます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
を使用できるようになります。ただし、無効な型を作成するような関数も適用できることを意味します。Car
String
reverse
Car
さらに一歩進んで、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を許可しないことです。それはさまざまな問題を混同しています。データ型自体にはInteger
3.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 |]
しかし今、私たちは本当に深いところから外れてしまい、あなたが望んでいたものに近づくことはできませんでした..あなたが何を望んでいるのかはまだかなり不明です