Haskell 幻影类型混淆?

Haskell 幻影类型混淆?,haskell,phantom-types,Haskell,Phantom Types,我对幻影类型的使用感到困惑: 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 phantom

我对幻影类型的使用感到困惑:

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

但是这编译得好吗?我做错了什么

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

这使得任何类型的
P1“aa”
形式的
Phantom a
,对于任何
a
,包括
数字

,构造函数的参数和构造函数所属类型的类型参数之间没有隐式连接。如果希望类型参数表示的类型出现在构造函数的参数中的任何位置,则需要显式声明它

您也可以在以下表达式中看到这一点:

Nothing
[]
第一个可以为任何
a
创建
可能是一个
,第二个可以为任何
a
创建一个列表
[a]

同样地

P1 "xyz"

根据您的示例,可以为任何
a

生成
幻影a
,其他答案已经解释了构造函数的类型

P1 :: Words -> Phantom a
意味着它能够为
a
的任何选择构造类型为
p1a
的值;特别是对于
a~数字的选择
。这就是函数调用的原因

phantomFunction (P1 "sdsdsd")
打字检查

现在,你如何解决这个问题?我想你想要
P1::Words->Phantom Words
?GADT允许您通过写入来约束构造值的类型中出现的类型变量

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

  • 确保
    P1
    具有类型
    Phantom Words
    ,因此不能使用它构建
    Phantom number
  • 允许使用
    虚字的函数通过仅在
    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
    

也许你想要一个GADT?