数据类型在函数参数内不起作用

Slo*_*ton 2 haskell

假设我具有以下数据类型:

data Zinf = NegInf | Z Integer | PosInf deriving (Eq, Ord, Show)
Run Code Online (Sandbox Code Playgroud)

Num因为所有必需的操作都已定义,所以它也是。例如PosInf + 1,当我键入内容时,解释会返回PosInf

现在,我导出另一种数据类型:

data Interval = Simple Integer | Complicated Zinf Zinf deriving (Eq, Show)
Run Code Online (Sandbox Code Playgroud)

现在,由于Zinf也是Num,我可以写下以下内容:

(Z 3) + 4
Run Code Online (Sandbox Code Playgroud)

我得到

(Z 7)
Run Code Online (Sandbox Code Playgroud)

我也可以测试

(Z 3) + 6 == 9
Run Code Online (Sandbox Code Playgroud)

然后解释返回True

我也可以写Complicated 3 (6*7)得到Complicated (Z 3) (Z 42)

最后,我使用以下“间隔”数据类型创建树:

data BinTree a = Empty | Node a (BinTree a) (BinTree a) deriving (Eq, Show)
type ITree = BinTree Interval
Run Code Online (Sandbox Code Playgroud)

现在,当我尝试编写此函数时:

moveBy :: ITree -> Integer -> ITree
moveBy Empty _ = Empty
moveBy (Node (Simple a) l r) i = (Node (Simple (a+i)) (moveBy l i) (moveBy r i))
moveBy (Node (Complicated a b) l r) i = (Node ( Complicated (a + i) (b + i) ) (moveBy l i) (moveBy r i)) 
Run Code Online (Sandbox Code Playgroud)

它产生以下错误:

* Couldn't match expected type `Zinf' with actual type `Integer'                                                         
* In the second argument of `(+)', namely `i'                                                                             
In the second argument of `Complicated', namely `(b + i)'                                                                     
In the first argument of `Node', namely `(Complicated (a + i) (b + i))'
Run Code Online (Sandbox Code Playgroud)

怎么来的?b应该是类型Zinfb+i还是类型Zinf,因为iInteger。并Complicated期望这种说法。

lef*_*out 8

现在,由于Zinf也是Num,我可以写下以下内容:

(Z 3) + 4
Run Code Online (Sandbox Code Playgroud)

是的,但(+)在这种情况下,不要Zinf -> Integer -> Zinf像看起来那样具有type ,这很重要。您可能会认为4那里有整数类型,但实际上没有:它实际上具有type Zinf。这令人惊讶,因为3 确实具有整数类型!

发生了什么:Haskell数字文字是多态的。

Prelude> :t 1
1 :: Num p => p
Run Code Online (Sandbox Code Playgroud)

因此,数字文字可以具有类型IntegerFloat或者甚至可以具有类型Zinf,具体取决于上下文的要求。在(Z 3) + 4这是Zinf为了4,所以4Zinf那里输入。大!

但是,这是行不通的Simple (a+i),因为在那里的类型i由签名/上下文固定为Integer。因此,您不能将其添加到中Zinf

但是,您可以执行以下操作:Integer通过将包裹在中,可以将任何值“升级”为多态数(例如数字文字)fromInteger。所以,你想要的是

moveBy (...) i = (Node (Simple (a + fromInteger i)) (...) (...)
Run Code Online (Sandbox Code Playgroud)

或等效地Simple (a + Z i)


实际上,数字文字的含义是它们也只是将“普通”整数文字包装在中fromInteger,以使其具有多态性。