我几乎没有实用功能来通过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版本吗?
答案 0 :(得分:2)
在这种情况下,我认为您不能将c
与Show
统一起来,因为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