在GHCI中正确行为,在文件中键入错误

时间:2014-06-23 23:50:13

标签: haskell types

鉴于定义:

 {-# 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]

3 个答案:

答案 0 :(得分:3)

我认为GHCi :t的结果在这种情况下基本上是错误的,你永远无法使用表达式run $ return x

问题在于,您的类定义中没有限制说明两个不同的Monad s m0m(使用与错误消息相同的名称)不能相同 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编译器的选项。我最终通过确保相关功能的编译选项和解释器选项相同来解决问题。