您可能不仅想要对HList进行
映射,而是想要对其进行
遍历,也就是所谓的
mapM
。您可能不感兴趣的是单个结果-
()
,而只是副作用,那么应该使用
mapM_
。
HList确实有一个通用工具,称为不出所料的hMapM_
。 对于任意受限制地多态函数使用它有点麻烦,但是对于打印来说,库已经准备好使用了:
Prelude Data.HList> let l = 1.*."2".*.HNil :: HList '[Int, String]
Prelude Data.HList> l
H[1,"2"]
Prelude Data.HList> hMapM_ HPrint l
1
"2"
如Noughtmare所评论的,与其他多态函数配合使用(而不必编写自定义类型)的方法是使用
Fun
,例如:
Prelude Data.HList> hMapM_ (Fun print :: Fun Show (IO ())) l
1
"2"
这段代码并不是太糟糕,但还是有点让人不爽。我会定义一个同义词,以允许使用TypeApplications来避免冗余:
{-# LANGUAGE TypeFamilies, RankNTypes, ConstraintKinds, UnicodeSyntax #-}
import Data.Kind
fun :: ∀ (cxt :: Type -> Constraint) getb
. (∀ a. (cxt a) => a -> getb) -> Fun cxt getb
fun = Fun
之后
Prelude Data.HList Data.Kind> :set -XTypeApplications
Prelude Data.HList Data.Kind> hMapM_ (fun @Show print) l
1
"2"
或者我们甚至可以将其变得更好
{-# LANGUAGE FlexibleContexts, AllowAmbiguousTypes #-}
h'MapM_ :: ∀ (cxt :: Type -> Constraint) l m
. (Monad m, HFoldr (Mapcar (Fun cxt (m ()))) [m ()] l [m ()])
=> (∀ a. (cxt a) => a -> m ()) -> HList l -> m ()
h'MapM_ f = hMapM_ (Fun f :: Fun cxt (m ()))
然后
Prelude Data.HList Data.Kind> h'MapM_ @Show print l
1
"2"
HCons 1 (HCons "2" HNil)
。 (注:这是一个 Haskell 编程语言中的数据结构,表示一个由数字1和字符串“2”组成的列表) - Willem Van OnsemH([1, "2"])
这样的速记法吗? - Functor[1,"2"]
已经是一个(普通)列表,因此该列表要求元素都是相同类型。可以使用quasiquoters或者模板Haskell,但不能使用简单的列表。 - Willem Van Onsem