ScopeTypeVariables无法帮助推断

时间:2014-02-18 07:52:29

标签: haskell

我几乎没有实用功能来通过sum类型转发类型类方法的调用。问题是我必须使用Proxy显式传递约束。我想使用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版本吗?

2 个答案:

答案 0 :(得分:2)

在这种情况下,我认为您不能将cShow统一起来,因为Show不是唯一可能与c (forall 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

也是类型检查。

答案 1 :(得分:0)

我不知道为gfold函数使用更明确的具体类型签名是否会破坏您尝试执行的操作的目的,但是您可以使用更通用的test类型检查{ {1}}版本写这样:

gfold