Haskell GHC型推理的困境
问题。有没有办法让这段代码在没有显式类型签名的情况下工作 代码。首先,实际上我有一个更好的MonadTrans替代类,灵感来自Data.Newtype。看起来是这样的,Haskell GHC型推理的困境,haskell,ghc,type-inference,typeclass,associated-types,Haskell,Ghc,Type Inference,Typeclass,Associated Types,问题。有没有办法让这段代码在没有显式类型签名的情况下工作 代码。首先,实际上我有一个更好的MonadTrans替代类,灵感来自Data.Newtype。看起来是这样的, {-# LANGUAGE FlexibleContexts, TypeFamilies #-} module Alt.Control.Monad.Trans where import Control.Monad class (Monad Yes, there is a way. Provide a grounded ins
{-# LANGUAGE FlexibleContexts, TypeFamilies #-}
module Alt.Control.Monad.Trans where
import Control.Monad
class (Monad Yes, there is a way. Provide a grounded instance for A
, and add NoMonomorphismRestriction
to the language pragma (in addition to the also required FlexibleInstances
and UndecidableInstances
).
However, the A
class will be unusable. There is no way for the compiler to know that there never will be a MonadTrans
instance with BaseMonad m = m
. Thus it cannot select an instance, ever, because it cannot know whether to use the instance from here or another one.
{-# LANGUAGE FlexibleContexts, TypeFamilies, FlexibleInstances, UndecidableInstances, NoMonomorphismRestriction #-}
module Trans (MonadTrans(..), A(..), minimize_call) where
import Control.Monad
class (Monad m, Monad (BaseMonad m)) => MonadTrans (m :: * -> *) where
type BaseMonad m :: * -> *
lift :: (BaseMonad m) α -> m α
class A m where
foo :: String -> m ()
data Foo a = Bork
instance Monad Foo where
return _ = Bork
_ >>= _ = Bork
instance A Foo where
foo _ = Bork
instance (A (BaseMonad m), MonadTrans m) => A m where
foo n = lift $ foo n
-- minimize_call :: A m => m ()
minimize_call = foo "minimize"
{LANGUAGE flexiblecontext,TypeFamilies-}
模块Alt.Control.Monad.Trans,其中
进口管制
是的,有一种方法。为提供固定实例,并将NomonomorphosmRestriction添加到语言pragma中,以及所需的FlexibleInstances和UndedicatableInstances
但是,A类将不可用。编译器无法知道永远不会有BaseMonad m=m的MonadTrans实例。因此,它永远无法选择实例,因为它不知道是从这里使用实例还是从另一个实例使用实例
使用ghc 6.12、7.0、7.2和7.4进行编译。如果没有签名,除非MR被关闭,否则minimize_调用必须获得单态类型。这无论如何都无法工作,因为约束am不是默认值。因此,必须关闭MR。但是,类型检查器仍然在追逐自己的尾巴,试图证明约束是可满足的。只有提升实例,它不能。如果你提供一个锚,它可以
但是提供一个类型签名要好得多。对不起,我应该想一想为什么我会选择另一个MonadTrans。。。现在,让我们假设它产生了更干净的代码,但我认为还有一个更重要的原因。有趣的问题。为什么不需要显式类型签名呢?是不是最小化_调用必须是某个固定值,而不是多态常量,或者你可以让它成为多态的,我不确定?如果它有某个固定类型,我宁愿记录它,如果它没有,我宁愿记录它。强迫读者在头脑中进行整个程序分析,以找出minimize_调用的类型似乎有点适得其反。@Ben,在这种情况下,为minimize_调用提供类型签名是一种不错的做法。但是,类型推断被破坏表明设计、编译器或与编译器的通信出现了问题,可能会导致问题,更不用说无法理解的错误消息了。谢谢,但我不希望模块中有固定实例。事实上,可能有多个固定实例,这取决于我有多少后端到我的编译器,并且假设使用一个特定的实例是不可取的。我已经启用了FlexibleInstances、FlexibleContexts和NomonomogormismRestriction。您可以使用未导出的虚拟monad,请参阅更新。minimize_调用的推断类型是m=>m,应该是这样,它不排除在其他地方使用不同的固定实例,只需要让类型检查器终止。实际上,不,你不能使用minimize_调用,或者foo。有或没有类型签名。嗯,我来看看你的a将无法使用的断言。我已经成功地使用了这个模式,但是可能有一些细微的差别,或者我没有尝试让它在多个基本实例中运行。