gat*_*ado 5 haskell type-inference typeclass ghc
我很困惑为什么这个代码用类型提示编译,但没有编译.不应该有任何实例歧义(有一个实例).
class Monad m => FcnDef ? m | ? -> m where
def :: String -> ? -- takes a name
instance Monad m => FcnDef (m ? -> m ?) m where
def s body = body
dummyTest :: forall m. Monad m => m ()
dummyTest = def "dummy" ((return ()) :: m ())
Run Code Online (Sandbox Code Playgroud)
另一方面,如果省略:: m ()
或所有类型声明,编译将失败并显示此错误,
No instance for (FcnDef (m0 () -> t0) m0)
arising from a use of `def'
Run Code Online (Sandbox Code Playgroud)
为了澄清,代码试图为多变量类型def
,因此可以编写例如
def "dummy2" "input" $ \in -> return ()
Run Code Online (Sandbox Code Playgroud)
这个问题比没有单态限制问题更有趣.如果添加了这样的代码,则将实例解析为具体类型,即
dummyTest = def "dummy" (return ())
g :: IO ()
g = dummyTest
Run Code Online (Sandbox Code Playgroud)
编译同样失败.
外部类型签名的需要是由单态限制引起的.
这个的赠品是你定义的左侧.
dummyTest = ...
Run Code Online (Sandbox Code Playgroud)
由于此定义没有任何参数,编译器将尝试使定义为单态.添加类型签名会覆盖此行为.
但是,正如您所指出的,这还不够.由于某种原因,编译器无法推断内部表达式的类型.为什么?我们来看看.是时候玩类型推理引擎了!
让我们从外部类型开始,尝试计算出内部表达式的类型.
dummyTest :: forall m. Monad m => m ()
dummyTest = def "dummy" (return ())
Run Code Online (Sandbox Code Playgroud)
类型def
是FcnDef ? m => String -> ?
,但这里我们已经应用def
了两个参数.这告诉我们?
必须是一个函数类型.我们称之为x -> y
.
然后我们可以很容易地推断出y
必须等于m ()
,以满足外部类型.此外,参数的类型return ()
是Monad m1 => m1 ()
,因此我们可以推断出def
我们正在寻找的类型必须具有类型FcnDef (m1 () -> m ()) m0 => def :: String -> m1 () -> m ()
.
接下来,我们将继续查找要使用的实例.唯一可用的实例不够通用,因为它需要m1
并且m
是相同的.所以我们大声抱怨这样的消息:
Could not deduce (FcnDef (m1 () -> m ()) m0)
arising from a use of `def'
from the context (Monad m)
bound by the type signature for dummyTest :: Monad m => m ()
at FcnDef.hs:10:1-51
Possible fix:
add (FcnDef (m1 () -> m ()) m0) to the context of
the type signature for dummyTest :: Monad m => m ()
or add an instance declaration for (FcnDef (m1 () -> m ()) m0)
In the expression: def "dummy" ((return ()))
In an equation for `dummyTest':
dummyTest = def "dummy" ((return ()))
Run Code Online (Sandbox Code Playgroud)
这里要注意的关键是,当我们试图推断出类型时,一个特定实例碰巧躺在身边的事实并没有影响我们的选择.
因此,我们不得不使用范围类型变量手动指定此约束,或者我们可以在类型类中对其进行编码.
class Monad m => FcnDef ? m | ? -> m where
def :: String -> ? -> ?
instance Monad m => FcnDef (m ?) m where
def s body = body
-- dummyTest :: forall m. Monad m => m ()
dummyTest = def "dummy" (return ())
Run Code Online (Sandbox Code Playgroud)
现在,类型推理引擎可以很容易地确定monad return
必须与结果中的monad相同,并且使用NoMonomorphismRestriction
我们也可以删除外部类型签名.
当然,我并不是百分之百确定你在这里想要完成什么,所以你必须在你想要做的事情中判断这是否有意义.
归档时间: |
|
查看次数: |
279 次 |
最近记录: |