Network包中的PortNumber根本没有构造函数,其定义和文档如下(或请参考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
...


使我感到困惑的是它如何使用Num实例创建PortNumber?我知道PortNumber是Num类的实例,可以将其视为Num,但是如何将Num实例(例如,文字10000)视为PortNumber?
构造具有构造函数为PortNumber PortNumber的PortID时,仅使用PortNumber 10000似乎可以。这是怎么发生的?

最佳答案

如果查看source,您将看到以下内容:

newtype PortNumber = PortNum Word16 deriving (Eq, Ord, Typeable)


马上。

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


不推荐使用的PortNum“不要使用PortNum构造函数。请使用Num实例。在下一发行版中将删除PortNum。”


这里的意思是PortNumberinstance of Num,因此您可以使用fromInteger-默认情况下,Haskell在看到120,...之类的整数时会执行此操作-这也是为什么

Prelude> :t 666
666 :: Num a => a


因此,不用使用构造函数PortNum 10000,而只需使用10000,它将在正确的上下文中自动成为PortNumber(请参见下面的内容)



对于PortId部分:PortNumber,有一个PortId构造函数(see source

data PortID =
      Service String
    | PortNumber PortNumber
    | UnixSocket String


)-因此,如果您使用PortNumber 10000,则实际上确实在使用Int -> PortNumber -> PortId路径,因为10000(使用fromInteger)被转换为PortNumber,然后插入到构造函数PortNumber中以获得PortId



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

Fun with type functions中有一个很好的示例,其确切用法如下:

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)

10-08 19:41