新しい個別の型type
を導入しないため、コンパイルされます。
型シノニム宣言は、古い型と同等の新しい型を導入します。[...]
型シノニムは、型シグネチャを読みやすくするための便利なメカニズムですが、厳密には構文上のメカニズムです。同義語とその定義は完全に交換可能です[...]
型シグネチャを含むあらゆるレベルで、制限なしで完全に。これは、さらに短い例で確認できます。
type Clown a b = Double
proof :: Clown a b -> Clown b a
proof = id
Clown a b
とClown b a
はどちらもDouble
— 実際のa
andに関係なく — どちらb
も と交換できるので、Double
のproof
型はDouble -> Double
です。
制約によって in の可能な型が制限されますa
がLength a
、結果の型のセマンティクスは実際には変更されません。代わりに、次を使用しますnewtype
。
data LengthUnit = Km | Meter
newtype Length (unit::LengthUnit) = MkLength {getLength :: Double}
onLength :: (Double -> Double) -> Length a -> Length a
onLength f = MkLength . f . getLength
divideByTwo ::Length l -> Length l
divideByTwo = onLength (/ 2)
getKm ::Double -> Length Km
getKm = MkLength
-- other code omitted
Length Km
とLength Meter
は異なるタイプであるため、必要なコンパイル用語エラーが発生します。
test.hs:25:44:
Couldn't match type 'Meter with 'Km
Expected type: Length 'Km
Actual type: Length 'Meter
In the second argument of `($)', namely `divideByTwo $ getMeter 1'
In the expression: isKm $ divideByTwo $ getMeter 1
In an equation for `this_should_not_compile_but_it_does':
this_should_not_compile_but_it_does
= isKm $ divideByTwo $ getMeter 1
test.hs:27:53:
Couldn't match type 'Meter with 'Km
Expected type: Length 'Km
Actual type: Length 'Meter
In the second argument of `($)', namely `getMeter 1'
In the expression: isKm $ getMeter 1