我想我想有效地做这样的事情:
class (forall z. ListZip z) => PlaneZip p where... --functions using z excluded
简而言之,但更确切地说,我想拥有
class A p where ... --definition excluded
class C p where
foo :: (A z) => p (z a) -> a
data Alpha a = ...definition excluded
data Beta a = ...definition excluded
instance A Alpha where --definition excluded
bar :: Beta (Alpha a) -> a
instance C Beta where
foo = bar
这是不可能的,因为foo
必须允许z
为A
,而不是Alpha
。如何使其成为可能,强制foo
必须某些 A
而不是任何 A
?
更详细地说,我有很多列表拉链,我想制作Comonad的实例。我没有创建列表拉链类型并围绕它创建大量包装器,而是决定创建一个类ListZip,并创建多个类型的实例。也就是说,
class (Functor z) => ListZip z where
leftMv :: z a -> z a
rightMv :: z a -> z a --further functions excluded
data ListZipInf a = ListZipInf ([a]) a ([a]) deriving (Show)
instance ListZip ListZipInf where... --functions excluded
data ListZipTorus a = ListZipTorus [a] a [a] deriving (Show)
instance ListZip ListZipTorus where.. --functions excluded
现在我想为2d列表制作类似的拉链 - 平面拉链 -
data PlaneZipInf a = PlaneZipInf (ListZipInf (ListZipInf a)) deriving (Show)
data PlaneZipTorus a = PlaneZipTorus (ListZipTorus (ListZipTorus a)) deriving (Show)
最后,我想制作一个类似的平面拉链类型类,这将允许我有一个默认的实现方式来拉出单个元素,这个列表拉链的'焦点',给出一种'解包方法' '平面拉链构造函数:
class PlaneZip p where
unwrap :: (ListZip z) => p (z (z a)) -> z (z a)
counit :: (ListZip z, Comonad z) => p (z (z a)) -> a
counit p =
let zs = unwrap p
in extract $ extract zs
然而,这不起作用,特别是
instance PlaneZip PlaneZipInf where
unwrap (PlaneZipInf zs) = zs
给我一个错误 - Could not deduce a ~ (ListZipInf (ListZipInf a))
它期望一个适用于任何ListZip
的函数,但我给它一个提供特定函数的函数。
我怎么能表达我希望unwrap
采用p (z (z a))
类型,其中z
是某种类型,它是ListZip
的一个实例,并生成一个{{} 1}}?
由于
答案 0 :(得分:3)
我可能会误解你的问题,但在你的情况下,你似乎总是会从嵌套列表拉链中创建平面拉链。如果是这种情况,那么简单地执行以下操作似乎更为可取:
{-# LANGUAGE StandaloneDeriving, FlexibleContexts, UndecidableInstances #-}
data PlaneZip z a = PlaneZipInf (z (z a))
deriving instance (Show a, Show (z a), Show (z (z a))) => Show (PlaneZip z a)
type PlaneZipInf a = PlaneZip ListZipInf a
type PlaneZipTorus a = PlaneZip ListZipTorus a
unwrap :: PlaneZip z a -> z (z a)
unwrap (PlaneZip zs) = zs
counit :: Comonad z => PlaneZip z a -> a
counit p =
let zs = unwrap p
in extract $ extract zs
如果您确实要确保z
中的PlaneZip z a
总是 ListZip
,则可以使用以下GADT
{-# LANGUAGE GADTs #-}
data PlaneZip z a where
PlaneZip :: ListZip z => z (z a) -> PlaneZip z a
如果情况并非如此,请随时回复 - 我相信还可以通过associated type families在此处完成其他工作,但上述解决方案要好得多。
答案 1 :(得分:1)
如何简单地使z
成为该类的参数?
{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies #-}
class (ListZip z, Comonad z) => PlaneZip p z | p -> z where
unwrap :: p (z (z a)) -> z (z a)
counit :: p (z (z a)) -> a
counit p =
let zs = unwrap p
in extract $ extract zs
instance PlaneZip PlaneZipInf ListZipInf where
unwrap (PlaneZipInf zs) = zs
| p -> z
语法是函数依赖;这意味着z
由p
决定,因此instance PlaneZip PlaneZipInf SomeOtherType
也是非法的。