2016-10-08 10 views
3

私はファントムタイプを使用するより混乱している:ファントムタイプの混乱?

type Words = String 
type Numbers = Int 

data NonPhantom = NP1 Words | NP2 Numbers deriving (Show) 

data Phantom a = P1 Words | P2 Numbers deriving (Show) 

nonPhantomFunction :: NonPhantom -> Int 
nonPhantomFunction r = 100 


phantomFunction :: Phantom Numbers -> Int 
phantomFunction a = 2001 


main = do 
    print $ nonPhantomFunction (NP1 "sdsdds") --can also pass NP2 here! 
    print $ phantomFunction (P1 "sdsdsd") --This shouldn't work!? 

私はphantomFunctionが明示的にその期待データ型NumbersPhantomを述べたように、このコードませは、コンパイルすることを期待。

これはうまくコンパイルされますか?私は間違って何をしていますか?

+2

たぶんあなたの代わりにGADTをしたいですか? – augustss

答えて

4
data Phantom a = P1 Words | P2 Numbers deriving (Show) 

これはNumbersを含む、任意aため、フォームPhantom aの任意のタイプのP1 "aa"なります。

1

コンストラクタの引数とコンストラクタが属する型の型引数の間に暗黙的な接続はありません。 type引数で指定された型をコンストラクタの引数のどこにでも表示させたい場合は、明示的にそれを記述する必要があります。

次の式でも、これを見ることができます:

Nothing 
[] 

最初のものは、任意のaための任意のa及び第二のリスト[a]ためMaybe aを作成することができます。

同様に

P1 "xyz" 

あなたの例からは、任意のa

0

他の回答についてPhantom aがすでにコンストラクタ

P1 :: Words -> Phantom a 

の種類は、それがすることが可能であることを意味していると説明していることができますの場合はP1 aの値を構成します。の場合はを選択します。;特に、a ~ Numbersの選択のために。このため、関数呼び出しは、

phantomFunction (P1 "sdsdsd") 

typechecksです。

これでどのように解決できますか? P1 :: Words -> Phantom Wordsをご希望ですか? GADTsは、あなたが構築された値の型で発生した型変数を制約することができ、あなたが

{-# LANGUAGE GADTs #-} 
data Phantom a where 
    P1 :: Words -> Phantom Words 
    P2 :: Numbers -> Phantom Numbers 

これを書きできるようにすることで、

  • あなたがPhantom Numbersを構築することはできませんのでP1 _Phantom Wordsを入力していることを確認しますそれに
  • Phantom Wordsを消費関数はAlのみ

  • P1に照合することによって徹底的なパターンマッチングを行うことを許可します Phantom a以上の多型であり、パターンマッチングに基づいて型を絞り込む(これは大きなものです)低関数なので、例えば以下のように書くことができます。

    dup :: Phantom a -> a 
    dup (P1 ws) = ws ++ ws -- Here, we have to return a Words, and ws is a Words, so ++ will work 
    dup (P2 n) = n + n -- Here, we have to return a Numbers, and x is a Numbers, so + will work