haskell - GADT 扩展会破坏多态性吗?

标签 haskell polymorphism gadt

是分机GADT在 Haskell 中破坏多态性,即使在不使用 GADT 的代码中?
这是一个有效但不使用 GADT 的示例


{-# LANGUAGE RankNTypes #-}
--{-# LANGUAGE GADTs #-}

newtype Fix1 f i = In1 { unFix1 :: f (Fix1 f) i }
mcata1 ::      (forall r k. (forall j. r j -> t j) -> f r k -> t k) 
            -> Fix1 f i
            -> t i
mcata1 f (In1 x) = f (mcata1 f) x


newtype Ret i = Ret {unRet :: (i -> Int) -> Int}


-- recusive type
data BushR i = NBR | CBR i (BushR (BushR i))

-- initial algebra
data BushF r i = NB | CB i (r (r i))
type Bush i = Fix1 BushF i

bsumm = mcata1 alg
  where alg :: forall i r. (forall j. r j -> Ret j) -> BushF r i -> Ret i
        alg r NB = Ret (const 0)
        alg r (CB x xs) = Ret (\f -> 
                f x + bsum xs (\ys -> bsum ys f))
                        where
                                bsum  = unRet . r
如果 GADTs启用我们得到一个编译错误
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE GADTs #-}

newtype Fix1 f i = In1 { unFix1 :: f (Fix1 f) i }
mcata1 ::      (forall r k. (forall j. r j -> t j) -> f r k -> t k) 
            -> Fix1 f i
            -> t i
mcata1 f (In1 x) = f (mcata1 f) x


newtype Ret i = Ret {unRet :: (i -> Int) -> Int}


-- recusive type
data BushR i = NBR | CBR i (BushR (BushR i))

-- initial algebra
data BushF r i = NB | CB i (r (r i))
type Bush i = Fix1 BushF i

bsumm = mcata1 alg
  where alg :: forall i r. (forall j. r j -> Ret j) -> BushF r i -> Ret i
        alg r NB = Ret (const 0)
        alg r (CB x xs) = Ret (\f -> 
                f x + bsum xs (\ys -> bsum ys f)) -- error
                        where
                                bsum  = unRet . r
-- • Occurs check: cannot construct the infinite type: i1 ~ r i1
--   Expected type: r (r i1)
--     Actual type: r i1
-- • In the first argument of ‘bsum’, namely ‘ys’
--   In the expression: bsum ys f
--   In the second argument of ‘bsum’, namely ‘(\ ys -> bsum ys f)’
-- • Relevant bindings include
可以通过复制绑定(bind)来修复
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE GADTs #-}

newtype Fix1 f i = In1 { unFix1 :: f (Fix1 f) i }
mcata1 ::      (forall r k. (forall j. r j -> t j) -> f r k -> t k) 
            -> Fix1 f i
            -> t i
mcata1 f (In1 x) = f (mcata1 f) x


newtype Ret i = Ret {unRet :: (i -> Int) -> Int}


-- recusive type
data BushR i = NBR | CBR i (BushR (BushR i))

-- initial algebra
data BushF r i = NB | CB i (r (r i))
type Bush i = Fix1 BushF i

bsumm = mcata1 alg
  where alg :: forall i r. (forall j. r j -> Ret j) -> BushF r i -> Ret i
        alg r NB = Ret (const 0)
        alg r (CB x xs) = Ret (\f -> 
                f x + bsum xs (\ys -> bsum2 ys f))
                        where
                                bsum   = unRet . r
                                bsum2  = unRet . r
这有什么深层次的原因吗?

最佳答案

启用 GADTs我们还隐式启用 MonoLocalBinds 这可以防止某些形式的 let - 和 where - 类型概括。
这会影响类型变量部分量化(i 下文)和部分自由(r 下文)的类型。

where bsum :: forall i. r i -> (i -> Int) -> Int
      bsum = unRet . r
一个简单的解决方案是提供显式类型注释以强制进行所需的泛化。
文档提供了 MonoLocalBinds 的基本原理,说明为什么在某些情况下限制泛化是有意义的。一个 blog post从 2010 年开始提供进一步的讨论。
博客中 Simon Peyton-Jones 的相关引用(稍微重新格式化,并使用与原始博客中相同的链接):

Why did we make it?

It’s a long story, but the short summary is this: I don’t know how to build a reliable, predictable type inference engine for a type system that has both

  • (a) generalisation of local let/where and
  • (b) local type equality assumptions, such as those introduced by GADTs.

The story is told in our paper “Let should not be generalised” and, at greater length, in the journal version “Modular type inference with local assumptions”.

关于haskell - GADT 扩展会破坏多态性吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66733625/

相关文章:

haskell -::运算符语法在有界类型类的上下文中如何工作?

haskell - Yesod 获取客户端 Ipv4/Ipv6 地址

types - 模块内的多态类型 (OCaml)

haskell - 不在范围内 : type constructor or class ‘∼’

haskell webframeworks 速度,GHCi 与编译

haskell - 无法将预期类型 (Int -> Int -> Int) 与实际类型 `(t0, t1, t2)' 匹配

java - 从子类访问父类的私有(private)实例变量?

c++ - 我如何将多态属性与 boost::spirit::qi 解析器一起使用?

pattern-matching - 在OCaml中什么时候需要驳回案件?

haskell - 如何从范围内的约束族派生类型类实例?