2014-02-18 89 views
2

我沒有什麼效用函數用於通過sum類型轉發類型方法的調用。問題是我必須使用代理顯式傳遞約束。我想只使用ScopedTypeVariables。ScopeTypeVariables無法幫助推理

下面是代碼

{-# 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版本嗎?

+0

這不叫'-XScopedTypeLevelVariablesOfAnyKind' ... – leftaroundabout

+0

@leftaroundabout這種解釋是有道理的,但不幸的是 –

回答

2

我不認爲你可以在這種情況下,統一cShow因爲Show是不是唯一可能的約束,在(forall e. c e => e -> d)匹配c。它可能只是以及一些其他類型的級,這意味着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 

也是類型的檢查。

+0

不能統一'與任何C',你甚至不能寫'FUNC =未定義:: FORALL cd。 (例如,e => e→d)'。傳遞給'gfold'的函數在'c'中必須是完全多態的,這實際上並不合理。 – user2407038

+0

這對於'gfold'的後一個版本來說不適合我。是不是爲了避免傳遞代理參數而改變'gfold'? –

0

我不知道,如果使用更明確的具體類型簽名您​​功能違背了你正在嘗試做的目的,但你可以讓test類型檢測,與更通用​​版本是這樣寫的:

test :: String 
test = (gfold :: ((forall e. Show e => e -> String) -> Foo -> String)) show $ I 1