5

问题。有没有办法让这段代码在没有显式类型签名的情况下工作?

代码。首先,我有一个实践中更好的替代MonadTrans课程,灵感来自Data.Newtype. 看起来像这样,

{-# LANGUAGE FlexibleContexts, TypeFamilies #-}

module Alt.Control.Monad.Trans where

import Control.Monad

class (Monad , Monad (BaseMonad )) => MonadTrans ( :: * -> *) where
    type BaseMonad  :: * -> *
    lift :: (BaseMonad ) α ->  α

然后,我有一个A带有 method的类foo,如果某个基本 monadM是 an A,那么任何转换后的 monadT M也是 an A。在代码中,

class A  where
    foo :: String ->  ()

instance (A (BaseMonad ), MonadTrans ) => A  where
    foo n = lift $ foo n

但是,如果我现在想创建一个foo替换它的第一个参数的快捷方式,那么我需要一个显式类型签名,否则编译器的上下文堆栈会溢出。

minimize_call :: A  =>  ()
minimize_call = foo "minimize"

有助于推断的可能信息。假设我们有一个关联的类型B :: * -> *。我在想我想告诉编译器B满足B t /= t,B (B t) /= B t等,即B在某种程度上是“单调的”——追逐关联类型相当于删除 newtype 包装器,它应该知道它不能永远删除 newtype 包装器,因此添加签名的上下文A是必要的。

4

1 回答 1

3

是的,有办法。为 提供一个有根据的实例A,并添加NoMonomorphismRestriction到语言杂注中(除了还必需的FlexibleInstancesand之外UndecidableInstances)。

但是,A该类将无法使用。编译器无法知道永远不会MonadTransBaseMonad m = m. 因此它永远无法选择一个实例,因为它不知道是使用这里的实例还是另一个实例。

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

与 ghc 6.12、7.0、7.2 和 7.4 一起编译。没有签名,minimize_call必须得到一个单态类型,除非 MR 被关闭。这无论如何都行不通,因为约束A m是不可默认的。因此,必须关闭 MR。但是随后类型检查器仍然追逐自己的尾巴,试图证明约束是可满足的。只有提升实例,它不能。如果你提供一个锚,它可以。

但是提供类型签名要好得多。

于 2012-02-15T22:12:41.443 回答