【发布时间】:2017-11-17 14:45:17
【问题描述】:
我有一个第一个类型类,它接受 leaf 的列表列表列表:
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, UndecidableInstances #-}
class ListTree leaf t where
lmap :: (leaf -> leaf) -> t -> t
instance ListTree leaf leaf where lmap f v = f v
instance ListTree leaf t => ListTree leaf [t] where lmap f v = map (lmap f) v
我有第二个类型类,它接受 a 的 2 元组和 3 元组:
class Tups a t where
tmap :: (a -> a) -> t -> t
instance Tups a (a,a) where tmap f (x,y) = (f x, f y)
instance Tups a (a,a,a) where tmap f (x,y,z) = (f x, f y, f z)
我想将它们结合起来描述以一些leaf 类型的 2 或 3 元组结尾的嵌套列表:
class LTTree leaf t where
ltmap :: (a -> a) -> t -> t
instance (Tups leaf x, ListTree x t) => LTTree leaf t where ltmap f v = lmap (tmap f) v
但是,最后一段代码给了我几个错误:
Could not deduce (LTTree leaf0 t)
from the context: LTTree leaf t
In the ambiguity check for ‘ltmap’
To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
Could not deduce (Tups leaf x0)
from the context: (Tups leaf x, ListTree x t)
In the ambiguity check for an instance declaration
To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
In the instance declaration for ‘LTTree leaf t’
如果我添加AllowAmbiguousTypes,我仍然会收到类似的错误。
不过,我可以通过内联其他两个类型类的代码来很好地定义 LTTree 类:
class LTTree leaf t where
ltmap :: (leaf -> leaf) -> t -> t
instance LTTree leaf (leaf,leaf) where ltmap f (x,y) = (f x, f y)
instance LTTree leaf (leaf,leaf,leaf) where ltmap f (x,y,z) = (f x, f y, f z)
instance LTTree leaf t => LTTree leaf [t] where ltmap f v = map (ltmap f)
如何将ListTree leaf t 类与Tups a t 类结合起来,以便列表树的叶子是a 的2 或3 元组?我不知道如果有帮助,请考虑添加额外的 GHC 扩展。
如果重要的话,我真正的用例是对列表树建模,其中叶子是行多态记录(使用 CTRex),其中记录中的每个字段都是某个类型类的实例(例如 Show,要打印树)。
【问题讨论】:
-
我认为你会从使用更直接的嵌套列表表示中获得更多好处:
data Nested a = Flat a | Nested (Nested [a]) -
几个问题。
t不是在LTTree中确定leaf吗?t不是在Tups中确定a吗?我认为您的课程需要fundeps 或类型族来表达这些依赖关系。不过,我什至不确定您是否真的需要这些课程:您要解决什么问题? -
这种用类型类表示数据的策略并没有真正给你任何东西,而且获得正确的编码显然不是微不足道的。正如其他评论者所指出的,为什么不将您的数据表示为……作为数据?您可以表示存在量化的记录,例如
data ConstrainedRec c where CRec :: Forall r c => Rec r -> ConstrainedRec c(其中Rec和Forall由 CTrex 提供)。 -
你没关系,
data方法可能更简单,也同样有效。我是 Haskell 的新手,所以我并不总是确定什么是适合这项工作的工具。学习如何将编码作为类型类进行编码是很有趣的。