记住这个反射计划:
{-# LANGUAGE ScopedTypeVariables, RecursiveDo #-}
import Control.Applicative
import Control.Monad
import Control.Monad.IO.Class
import Prelude hiding (div)
import Reflex.Dom
import qualified Data.Map as M
clickMe :: MonadWidget t m => m (Event t ())
clickMe = do
rec (e,_) <- elAttr' "button" M.empty (display c)
c :: Dynamic t Int <- count (domEvent Click e)
return $ domEvent Click e
div :: forall t m a . MonadWidget t m => m a -> m a
div = elAttr "div" ("style" =: "border : 1px solid black")
app :: forall t m . MonadWidget t m => m ()
app = div $ do
aClicks <- clickMe
bClicks <- clickMe
a <- count aClicks
b <- count bClicks
l <- combineDyn (\a b -> replicate (a-b) ()) a b
simpleList l (const clickMe)
return ()
main = mainWidget app
如果从div
或app
中删除类型注释,程序将无法使用巨大的可怕类型错误进行编译。 如果你删除它们,它将再次编译。从程序员的角度来看,当有人试图逐步注释未注释的程序时,这会给用户带来糟糕的体验。将未正确的类型注释添加到未注释的术语中会导致编译器错误,这会导致程序员认为他的类型错误。
This is the error you get by removing div
's annotation.
为什么会这样?
答案 0 :(得分:4)
这是由于单态性限制。当编译器在没有类型注释的情况下对顶级绑定进行类型检查时,如果该类型具有约束并且该函数没有语法参数,则不会分配多态类型,这是两者的情况。你的功能。
但是,如果您不包含 类型签名,则它仍然无法编译。在你的情况下,你给了它一些额外的信息(foo = [app, _]
部分),并且由于某种原因它选择了单态类型 - 我不知道你的环境发生了什么变化,但这不是标准行为。
这是一个简单的文件,提炼出您遇到的问题:
{-# LANGUAGE RankNTypes, KindSignatures, MultiParamTypeClasses, FunctionalDependencies #-}
module Test where
import Prelude hiding (div)
class MonadWidget t (m :: * -> *) | m -> t
div :: forall t m a . MonadWidget t m => m a -> m a
div = (undefined :: forall t m a . MonadWidget t m => m a -> m a)
app :: forall t m . MonadWidget t m => m ()
app = (div (undefined :: forall t m . MonadWidget t m => m ())
:: forall t m . MonadWidget t m => m () )
如果您注释掉任何类型签名,或两者都注释,您将遇到错误。
但是,注释掉任何顶级类型签名,但使用ghc -XNoMonomorphismRestriction Test.hs
运行它,它将在每个配置中成功编译。 Here are a few tests。
答案 1 :(得分:1)
正如Reid Barton在评论中指出的那样,这归因于The Dreaded Monomorphism Restriction。
以下是简化示例:
foo :: Monad m => m a -> m a
foo = (>>= return)
bar :: Monad m => m ()
bar = foo (return ())
启用单态限制并且foo
的类型签名被注释时:
foo
并失败,因为没有默认的Monad
实例:因使用'&gt;&gt; ='而没有(Monad m0)的实例 类型变量'm0'是不明确的
foo
使用bar
会导致另一个我无法解释的错误无法将类型'm0'与'm'匹配 因为类型变量'm'会逃避其范围
添加{-# LANGUAGE NoMonomorphismRestriction #-}
pragma修复此问题并允许逐步添加类型签名。