鉴于定义:
{-# LANGUAGE ExistentialQuantification, TypeFamilies, FlexibleInstances, FlexibleContexts, ScopedTypeVariables #-}
class Monad m => RunableMonad m where
type ReturnType m :: * -> *
run :: m a -> ReturnType m a
当我输入GHCI时
:t \x -> [run $ return x]
它给了我正确的表达类型:
\x -> [run $ return x] :: RunableMonad m => a -> [ReturnType m a]
但是当我将定义下面的定义放入文件时,它会给我一个类型错误:
single :: RunableMonad m => a -> [ReturnType m a]
single x = [run $ return x]
Could not deduce (ReturnType m0 ~ ReturnType m)
from the context (RunableMonad m)
bound by the type signature for
single :: RunableMonad m => a -> [ReturnType m a]
at concurrency-simulator.hs:467:11-49
NB: ‘ReturnType’ is a type function, and may not be injective
The type variable ‘m0’ is ambiguous
Expected type: a -> [ReturnType m a]
Actual type: a -> [ReturnType m0 a]
In the ambiguity check for:
forall a (m :: * -> *). RunableMonad m => a -> [ReturnType m a]
To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
In the type signature for ‘single’:
single :: RunableMonad m => a -> [ReturnType m a]
答案 0 :(得分:3)
我认为GHCi :t
的结果在这种情况下基本上是错误的,你永远无法使用表达式run $ return x
。
问题在于,您的类定义中没有限制说明两个不同的Monad
s m0
和m
(使用与错误消息相同的名称)不能相同 ReturnType
。
这意味着,在查看使用run $ return x
的上下文时,GHC可能能够推断出结果ReturnType m a
的内容,并且可以推断x
的类型a
是什么,但它无法从实际的monad m
推断出来。
但是,您应该明确地告诉它:run (return x :: WhateverTypeYouReallyWant)
。
只有在像run
这样的表达式上使用return x
时才需要添加显式类型注释,这样的多态性可以属于多个monad。 (或者在这种情况下,任何monad。)
答案 1 :(得分:2)
您可以编译代码,但它永远不可用。通常,如果您看到推荐AllowAmbiguosTypes
的错误,则这是一个红色鲱鱼。它很少能解决您的问题,但有时(如本例所示)会使其看起来固定:
{-# LANGUAGE
, ExistentialQuantification
, TypeFamilies
, FlexibleInstances
, FlexibleContexts
, ScopedTypeVariables
, AllowAmbiguousTypes #-}
class Monad m => RunableMonad m where
type ReturnType m :: * -> *
run :: m a -> ReturnType m a
single :: forall m a . RunableMonad m => a -> ReturnType m a
single x = run (return x :: m a)
但是我说:
import Data.Functor.Identity
instance RunableMonad Identity where
type ReturnType Identity = Identity
run = id
这将产生极其神秘的错误:
>:t single 'a' :: Identity Char
<interactive>:1:1:
Couldn't match type `ReturnType m0' with `Identity'
The type variable `m0' is ambiguous
Expected type: Identity Char
Actual type: ReturnType m0 Char
In the expression: single 'a' :: Identity Char
要了解为什么你的功能毫无意义,请考虑
instance RunableMonad [] where
type ReturnType [] = Identity
run = Identity . head
>:t single 'a'
single 'a' :: RunableMonad m => ReturnType m Char
如何选择要使用的类型类实例?您可能会错误地认为,由于m
仍然存在于类型中,而您仍然有RunableMonad m
,因此您可以选择m
RunableMonad
作为ReturnType
。但由于ReturnType m Char ~ Identity Char
是一个类型函数,并且类型函数不是单射函数,即使我们有m ~ Identity
,我们也无法推断出m ~ []
- 显然这不是考虑到single
在这里是一个完全有效的选择这一事实的意义。
在我看来,函数AmbiguousTypes
不应该存在。编译器最初拒绝它的事实是完全正确,并且您可以使用single
进行编译这一事实是错误的。
如果您真的必须拥有class Monad m => RunableMonad m where
data ReturnType m a
run :: m a -> ReturnType m a
instance RunableMonad Identity where
newtype ReturnType Identity a = RT_Id a deriving Show
run (Identity a) = RT_Id a
instance RunableMonad [] where
newtype ReturnType [] a = RT_List a deriving Show
run = RT_List . head
single x = run (return x) -- type here will be inferred
功能,则需要执行以下操作:
{{1}}
答案 2 :(得分:0)
我没有ghc 7.8,所以这只是猜测。
我认为您可以尝试将AllowAmbiguousTypes
添加到
{-# LANGUAGE ExistentialQuantification, TypeFamilies, FlexibleInstances, FlexibleContexts, ScopedTypeVariables #-}
在源文件的开头,或查找ghc
的命令行选项,以便与AllowAmbiguousTypes
进行编译。我有一个类似的问题GHCi和ghc命令行有不同的行为。事实证明,默认情况下,ghci打开一组不同于ghc编译器的选项。我最终通过确保相关功能的编译选项和解释器选项相同来解决问题。