如何在Haskell中迭代异构递归值

如何在Haskell中迭代异构递归值,haskell,Haskell,我看到了HList的软件包,但我认为这对于我所需要的东西来说太过分了 我有这个: data a :*: b = a :*: b deriving (Show, Eq) 我可以通过以下方法成功地完成这项工作: prepend :: a -> b -> a :*: b prepend a b = a :*: b 但是我希望能够以某种方式遍历“列表”并使用元素进行操作,但不确定如何操作。这里的以及可能有用的 基本迭代相对简单(前提是您能够轻松地思考本质上的Prolog),按元素类型(或

我看到了HList的软件包,但我认为这对于我所需要的东西来说太过分了

我有这个:

data a :*: b = a :*: b deriving (Show, Eq)
我可以通过以下方法成功地完成这项工作:

prepend :: a -> b -> a :*: b
prepend a b = a :*: b
但是我希望能够以某种方式遍历“列表”并使用元素进行操作,但不确定如何操作。

这里的以及可能有用的

基本迭代相对简单(前提是您能够轻松地思考本质上的Prolog),按元素类型(或标签)匹配记录会让事情变得棘手:根据类型相等性做一些事情目前需要重叠实例,您将无法决定是否相等(大多数?全部?)多态类型

类型匹配很可能是“对元素做点什么”所需要的,这取决于什么是元素;删除很容易,应用一个函数(其参数必须与元素类型匹配)不是一件小事,但如果您可以给出元素的数字索引,则应该可以不使用编译器扩展

(编辑:这假设您希望对列表应用第一类函数。Rampion的回答显示了如何使用普通类型类轻松匹配类型,但类型类不能作为值传递。)


因此,最终可能会发现HList或葡萄柚记录并没有过度使用。

请注意,您已经可以通过两种方式迭代列表:

ghci> let hetlist = (1 :: Int) :*: ("two" :: String) :*: (3.0 :: Double) :*: ()
ghci> hetlist
((1 :*: "two") :*: 3.0) :*: ()
ghci> hetlist == hetlist
True
您可以使用自己的TypeClass来模拟这一点:

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) :*: ()
或者,您也可以使用
和包装器类型执行同样的操作,
这样就不必定义自己的列表类型

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

附议@barsoap的建议。如果您确实需要可扩展性,那么可能很难比HList更简单。HList文件(当然是草稿)评论说,在类型级别列表中使用Nil比省略Nil更容易。问题中:*:的定义是pair,因此没有Nil..oO(Haskell的类型系统非常先进,可以使函数不是第一类;)是一个表达式问题!小心,
:*:
现在是
GHC.Generics中的(非)标准类型