我看到了HList包,但我认为这对我所需要的东西来说太过分了。
我有这个:
data a :*: b = a :*: b deriving (Show, Eq)
我可以成功地使用它:
prepend :: a -> b -> a :*: b
prepend a b = a :*: b
但是我希望能够以某种方式遍历“列表”并使用元素进行操作,但不知道如何操作。
答案 0 :(得分:5)
此处可能会使用HList paper以及grapefruit-records paper。
基本迭代相对简单(假设您在基本上是Prolog时很容易思考),按元素类型(或标签)匹配记录是事情变得毛茸茸的事情:根据类型相等做一些事情当前需要OverlappingInstances
,你将无法决定(大多数?所有?)多态类型的相等性。
匹配类型可能就是你需要“对元素做些什么”,取决于什么是什么;删除很简单,应用一个函数,其参数必须与元素类型匹配,这不是微不足道的,但是如果你可以给出元素的数字索引,那么应该可以不使用编译器扩展。
(编辑:这假定您要将第一类函数应用于列表.Rampion的答案显示了如何使用vanilla类型类轻松匹配类型,但是类型类不能作为值传递。)
所以,最终,可能会发现HList或者葡萄柚记录毕竟不是过度杀伤。
答案 1 :(得分:4)
请注意,您可以通过两种方式遍历列表:
ghci> let hetlist = (1 :: Int) :*: ("two" :: String) :*: (3.0 :: Double) :*: ()
ghci> hetlist
((1 :*: "two") :*: 3.0) :*: ()
ghci> hetlist == hetlist
True
您可以使用自己的类型类来模仿:
class DoStuff a where
dostuff :: a -> a
instance DoStuff Int where dostuff i = 2*i
instance DoStuff String where dostuff s = s ++ s
instance DoStuff Double where dostuff d = d / 2
instance DoStuff () where dostuff () = ()
instance (DoStuff a, DoStuff b) => DoStuff (a :*: b) where
dostuff (a :*: b) = dostuff a :*: dostuff b
然后自动遍历集合
ghci> dostuff hetlist
((2 :*: "twotwo") :*: 1.5) :*: ()
或者,您可以使用ExistentialQuantification
和包装类型执行相同的操作,
然后你就不必定义自己的列表类型了。
data DoStuffWrapper = forall a. (DoStuff a) => DoStuffWrapper a
homlist = [ DoStuffWrapper (1 :: Int)
, DoStuffWrapper ("two" :: String)
, DoStuffWrapper (3.0 :: Double)
]
homlist' = map (\(DoStuffWrapper a) -> DoStuffWrapper (dostuff a)) homlist