2016-10-08 2 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 явно заявляет о своем ожидающем типе данных Phantom из Numbers.

Однако это скомпилировано? Что я делаю не так?

+2

Может быть, вы хотите GADT вместо этого? – augustss

ответ

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

P1 "aa" Это делает любого типа формы Phantom a для любого a, в том числе Numbers.

1

Нет никакой неявной связи между аргументом конструктора и аргументом типа того типа, к которому принадлежит конструктор. Если вы хотите, чтобы тип, обозначенный аргументом типа, отображался где угодно в аргументах конструктора, вам нужно явно указать его.

Вы можете увидеть это также в следующих выражениях:

Nothing 
[] 

Первый можно создать Maybe a для любого a и второй список [a] для любого a.

Аналогично

P1 "xyz" 

из вашего примера можно сделать Phantom a для любого a

0

Другие ответы уже выяснили, что тип вашего конструктора

P1 :: Words -> Phantom a 

означает, что он способен построить значение типа P1 a для любое выбор 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 

Это

  • Убедитесь P1 _ имеет тип Phantom Words, так что вы не можете построить Phantom Numbers с ним
  • Разрешить функции, потребляющие Phantom Words сделать исчерпывающее сопоставление с образцом лишь соответствие с P1
  • Al низкие функции, которые являются полиморфными по сравнению с 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 
    
Смежные вопросы