类型同义词会导致类型错误 [英] Type synonym causes type error
问题描述
作为我之前问题的后续工作,使用makeLenses,class约束和类型同义词我有一个新的类型错误,我想了解。
类型错误是由引入类型同义词 type S =(Num n)=>在下面的例子中,状态n
。 $ b
{ - #LANGUAGE TemplateHaskell# - }
{ - #LANGUAGE RankNTypes# - }
模块Foo其中
导入Control.Lens
数据状态a =状态{_a :: a
}派生Show
makeLenses''状态 - 需要TemplateHaskell
- |智能构造函数在记录字段_a上强制执行类约束。
mkState ::(Num a)=> a - >州a
mkState n =州{_a = n}
doStuff1 :: Num a =>状态a - >说明
doStuff1 s = s&一个%〜(* 2)
test1a = doStuff1 $ mkState 5 - 结果为状态{_a = 10.0}
test1b = doStuff1 $ mkState 5.5 - 结果为状态{_a = 11.0 }
type S =(Num n)=>状态n - 需要RankNTypes扩展
doStuff2 :: S - > S
doStuff2 s = s& a%〜(* 2)
test2a = doStuff2 $ mkState 5 - 状态结果{_a = 10.0}
--test2b = doStuff2 $ mkState 5.5 - 类型错误。
如果我取消注释 test2b
错误。
无法推断(小数n)上下文(Num n)
被上下文期望的类型所限制:Num n =>状态n
在Foo.hs:32:10-32
可能的修正:
添加(小数n)到上下文中预期的
a类型:Num n => ;状态n
在`mkState'的第一个参数中,也就是`5.5'
在`($)'的第二个参数中,即`mkState 5.5'
在表达式中:doStuff2 $ mkState 5.5
我希望能够理解为什么引入的类型同义词会导致此错误以及如何解码错误消息。
S - > S
不等于 forall n。 Num n =>状态n - >州n
。它相当于(全部n。n = n>状态n) - > (全部num n =>州n)
。前者意味着,对于所有的数字类型 n
,我们可以传递一个 State n
并返回一个 State n
(对于相同类型 n
)。后者意味着我们为所有数字类型 n
传递了一些可以是 State n
的东西,对于所有类型 n
,可以是 State n
。换句话说,参数和结果都是多态的。
这意味着您传入的参数必须包含 Num n => gt ;状态n
,不是一个更具体的类型,比如说, State Int
。对于 5
,这是真的,它的类型是 Num n => n
,但不是 5.5
,其类型为 Fractional n => n
。
As a follow-up to my previous question Using makeLenses, class constraints and type synonyms together I've got a new type error I would like to understand.
The type error is caused by the introduction of the type synonym type S = (Num n) => State n
in the below example.
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE RankNTypes #-}
module Foo where
import Control.Lens
data State a = State { _a :: a
} deriving Show
makeLenses ''State -- Requires TemplateHaskell
-- | Smart constructor enforcing class constraint on record field _a.
mkState :: (Num a) => a -> State a
mkState n = State {_a = n}
doStuff1 :: Num a => State a -> State a
doStuff1 s = s & a %~ (*2)
test1a = doStuff1 $ mkState 5 -- results in State {_a = 10.0}
test1b = doStuff1 $ mkState 5.5 -- results in State {_a = 11.0}
type S = (Num n) => State n -- Requires the RankNTypes extensions
doStuff2 :: S -> S
doStuff2 s = s & a %~ (*2)
test2a = doStuff2 $ mkState 5 -- Results in State {_a = 10.0}
--test2b = doStuff2 $ mkState 5.5 -- Type error.
If I uncomment test2b
I get the following error.
Could not deduce (Fractional n) arising from the literal `5.5'
from the context (Num n)
bound by a type expected by the context: Num n => State n
at Foo.hs:32:10-32
Possible fix:
add (Fractional n) to the context of
a type expected by the context: Num n => State n
In the first argument of `mkState', namely `5.5'
In the second argument of `($)', namely `mkState 5.5'
In the expression: doStuff2 $ mkState 5.5
I would like to be able to understand why the introduced type synonym causes this error and how to decipher the error message.
S -> S
is not equivalent to forall n. Num n => State n -> State n
. It's equivalent to (forall n. Num n => State n) -> (forall n. Num n => State n)
. The former would mean that, for all numeric types n
, we can pass in a State n
and get back a State n
(for the same type n
). The latter means that we pass in something that can be a State n
for all numeric types n
and we get back something that can be a State n
for all type n
. In other words both the argument and the result are polymorphic.
What this means is that the argument you pass in must have type Num n => State n
, not a more concrete type like, say, State Int
. This is true for 5
, which has the type Num n => n
, but not 5.5
, which has the type Fractional n => n
.
这篇关于类型同义词会导致类型错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!