Haskell ScopeTypeVariables无法帮助推断

Haskell ScopeTypeVariables无法帮助推断,haskell,Haskell,我有一个通过sum类型转发type类方法调用的小实用函数。问题是我必须使用代理显式地传递约束。我只想使用ScopedTypeVariables 这是密码 {-# LANGUAGE TypeOperators #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE

我有一个通过sum类型转发type类方法调用的小实用函数。问题是我必须使用代理显式地传递约束。我只想使用ScopedTypeVariables

这是密码

{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE DeriveGeneric #-} 
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiParamTypeClasses #-}
module Mitsuba.Generic where
import GHC.Generics
import Data.Proxy

class GFold f c b where
    genericFold :: p c -> (forall e. c e => e -> b) -> f a -> b 

instance GFold a c d => GFold (M1 x y a) c d where
   genericFold p f (M1 x) = genericFold p f x

instance ( GFold a c d
         , GFold b c d
         ) => GFold (a :+: b) c d where
   genericFold p f = \case
      L1 x -> genericFold (Proxy :: Proxy c) f x
      R1 x -> genericFold (Proxy :: Proxy c) f x

instance c a => GFold (K1 i a) c d where
   genericFold p f (K1 x) = f x

gfold :: (Generic a, GFold (Rep a) c d) 
      => p c -> (forall e. c e => e -> d) -> a -> d
gfold p h x = genericFold p h $ from x

data Foo = I Int | D Double | B Bool
   deriving(Generic)

test :: String
test = gfold (Proxy :: Proxy Show) show $ I 1
所以测试工作就像我希望的那样。但是,我希望“gfold”函数如下所示

gfold :: forall a c d. (Generic a, GFold (Rep a) c d) 
      => (forall e. c e => e -> d) -> a -> d
gfold h x = genericFold (Proxy :: Proxy c) h $ from x
进行编译,但测试会给出以下错误

src/Generic.hs:39:8:
Could not deduce (c0 Bool, c0 Double, c0 Int)
  arising from a use of `gfold'
In the expression: gfold show
In the expression: gfold show $ I 1
In an equation for `test': test = gfold show $ I 1

src/Generic.hs:39:14:
Could not deduce (Show e) arising from a use of `show'
from the context (c0 e)
  bound by a type expected by the context: (c0 e) => e -> String
  at src/Mitsuba/Generic.hs:39:8-17
Possible fix:
  add (Show e) to the context of
    a type expected by the context: (c0 e) => e -> String
In the first argument of `gfold', namely `show'
In the expression: gfold show
In the expression: gfold show $ I 1

无论如何,我可以编写我想要的gfold版本吗?

我认为在这种情况下,你不能将
c
Show
统一起来,因为
Show
不是
中匹配
c
的唯一可能约束(对于所有e.c e=>e->d)
。它也可以是其他类型的类,这意味着
Show
,例如:

class Show a => MyShow a where
  myShow :: a -> String
  myShow a = "foo: " ++ show a

instance MyShow Int
instance MyShow Double
instance MyShow Bool
现在呢

test = gfold (Proxy :: Proxy MyShow) show $ I 1

还有类型检查。

我不知道对
gfold
函数使用更明确的具体类型签名是否会违背您尝试执行的目的,但您可以使用更通用的
gfold
版本进行
测试
类型检查,如下所示:

test::String
test=(gfold::((对于所有e.Show e=>e->String)->Foo->String))Show$I 1

它没有被称为任何类型的XScopedTypeLevelVariables
。@LeftAround关于这个解释是有道理的,但不幸的是,你不能用任何东西统一
c
,你甚至不能为所有c d编写
func=undefined::函数。(对于所有e.c.e=>e->d)
。传递给
gfold
的函数在
c
中必须是完全多态的,这实际上是没有意义的。这不会为我检查后一版本的
gfold
。对
gfold
的更改不是为了避免传递代理参数吗?