两个函数使用类型注释进行编译。删除一个注释 - 不编译。再次删除两个 - 编译。为什么? [英] Two functions compile with type annotations. Remove one annotation - doesn't compile. Remove two - compiles again. Why?

查看:172
本文介绍了两个函数使用类型注释进行编译。删除一个注释 - 不编译。再次删除两个 - 编译。为什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

注意这个Reflex程序:

$ $ p $ {code> { - #LANGUAGE ScopedTypeVariables,RecursiveDo# - }

导入Control.Applicative
导入Control.Monad
导入Control.Monad.IO.Class
导入Prelude隐藏(div)
导入Reflex.Dom
导入限定数据。映射为M

clickMe :: MonadWidget tm => m(事件t())
clickMe = do
rec(e,_)< - elAttr'按钮M.empty(显示c)
c :: Dynamic t Int< - count(domEvent点击e)
返回$ domEvent点击e

div :: forall tma。 MonadWidget t m => m a - > m a
div = elAttrdiv(style=:border:1px solid black)

app :: forall t m。 MonadWidget t m => m()
app = div $ do
ClickClick< - clickMe
bClicks< - clickMe
a< - count aClicks
b< - count bClicks
< - combineDyn(\ ab - > replicate(ab)())ab
simpleList l(const clickMe)
return()
$ b main = mainWidget app

如果您从 div 或 app ,程序将不会编译一个巨大的,可怕的类型错误。 如果您将两者都删除,则会再次编译。从程序员的角度来看,当有人尝试对未注释的程序进行增量式注释时,会给用户带来可怕的体验。没有意义的是,将正确的类型注释添加到未注释的术语会导致编译器错误,并且会导致程序员认为他的类型错误。

这是通过删除 div 的注释获得的错误。



这些是推断的类型。



为什么发生这种情况?

解决方案

这是由于单态的限制。当编译器在没有类型注释的情况下对顶级绑定进行类型检查时,如果该类型具有约束并且该函数没有语法参数(它们都是 ),则它不会分配多态类型你的功能。然而,如果你包含 类型签名,它仍然不能编译。 在你的情况下,你给了它一些额外的信息( foo = [app,_] 部分),并且由于某种原因它选择了单形类型 - 我没有知道你的环境发生了什么变化,但这不是标准行为。



以下是一个简单的文件,介绍您遇到的问题:

  { - #LANGUAGE RankNTypes,KindSignatures,MultiParamTypeClasses,FunctionalDependencies# - } 

模块测试其中

前导隐藏(div)

类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 tm。MonadWidget tm => m())
:: forall tm。MonadWidget tm => m())

如果您注释掉任一类型签名或两者都会遇到错误。
但是,注释掉任何顶级类型签名,但是使用 ghc -XNoMonomorphismRestriction Test.hs 运行它,并且它会在每个配置中成功编译。 此处 a> a 少数 测试

Mind this Reflex program:

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

If you remove the type annotation from either div or app, the program won't compile with a huge, scary type error. If you remove both, it will compile again. From a programmer's perspective, this gives a terrible user experience when someone is trying to incrementally annotate an unannotated program. It makes no sense that adding a correct type annotation to an unannotated term causes a compiler error, and it leads the programmer to think he got the type wrong.

This is the error you get by removing div's annotation.

Those are the inferred types.

Why this happens?

解决方案

This is due to to the monomorphism restriction. When the compiler is typechecking a top-level binding without a type annotation, it will not assign a polymorphic type if that type has a constraint and the function has no syntactic argument, which is the case for both of your functions.

However, if you include neither type signature, it still doesn't compile. In your case, you gave it some extra information (the foo = [app, _] part) and for some reason it chose to pick a monomorphic type - I don't know what changed about your environment but that isn't standard behaviour.

Here is a simple file distilling the issue you are having:

{-# 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 () )

If you comment out either type signature, or both, you will be met with an error. However, comment out any top-level type signature, but run this with ghc -XNoMonomorphismRestriction Test.hs and it will compile successfully in every configuration. Here are a few tests.

这篇关于两个函数使用类型注释进行编译。删除一个注释 - 不编译。再次删除两个 - 编译。为什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆