如何在Haskell中创建具有空构造函数的数据类型的值?

hli*_*liu 2 constructor haskell

Network包中的PortNumber 根本没有构造函数,其定义和doc如下(或请参考https://hackage.haskell.org/package/network-2.6.2.1/docs/Network.html):

data PortNumber

Use the Num instance (i.e. use a literal) to create a PortNumber value with
the correct network-byte-ordering. You should not use the PortNum constructor.
It will be removed in the next release.

instances
...
Num PortNumber
...
Run Code Online (Sandbox Code Playgroud)

令我困惑的是它如何使用Num实例创建一个PortNumber?我知道PortNumber是类Num的一个实例,它可以被认为是一个Num,但它如何才能看到Num实例(例如文字10000)作为PortNumber?在构造具有构造函数的PortID时PortNumber PortNumber,似乎可以使用PortNumber 10000.这是怎么发生的?

Car*_*ten 6

如果你看一下你看到的来源:

newtype PortNumber = PortNum Word16 deriving (Eq, Ord, Typeable)
Run Code Online (Sandbox Code Playgroud)

马上.

如果您查看文档,您也会看到此警告:

DEPRECATED PortNum"不要使用PortNum构造函数.使用Num实例.将在下一版本中删除PortNum."

这里有什么意思的是,PortNumber是一个实例Num,因此你可以使用fromInteger-当它看到一个整数数字像这哈斯克尔的默认操作1,20... -这也就是为什么

Prelude> :t 666
666 :: Num a => a
Run Code Online (Sandbox Code Playgroud)

因此,您可以使用构造函数, 而不是使用构造函数,它将自动在正确的上下文中(请参阅下文)PortNum 1000010000PortNumber


对于PortId部分:PortNumber有一个构造函数PortId(参见来源:

data PortID =
      Service String
    | PortNumber PortNumber
    | UnixSocket String
Run Code Online (Sandbox Code Playgroud)

) - 所以,如果你使用PortNumber 10000你确实正在使用Int -> PortNumber -> PortId路径,因为10000(使用fromInteger)被转换为a PortNumber然后插入构造函数 PortNumber以获得PortId


除此之外,您可能会看到带有数据定义的示例- 但由于Haskell很懒惰,您通常仍然可以使用它undefined :: MyEmptyType来获取无论如何都不会被评估的地方的.

使用类型函数的Fun中 有一个很好的例子:

data Zero
data Succ n

class Nat n where
   toInt :: n -> Int

instance Nat Zero where
   toInt _ = 0

instance (Nat n) => Nat (Succ n) where
   toInt _ = 1 + toInt (undefined :: n)
Run Code Online (Sandbox Code Playgroud)