如何在HList上编写异构列表?

Fun*_*tor 3 haskell

我想使用HList:异构列表

import Data.HList (HList)至此就完成了库的安装。

现在调查https://bitbucket.org/HList/hlist/src/master/examples/HListExample/并不能帮助我开始编写代码。

我想做的是,

  1. 创建一个 hello-world 异构列表,例如H[1, "2"](完全不确定语法)

  2. 将异构列表映射到print每个列表。

有没有人熟悉如何使用HList

Nou*_*are 5

您可以使用hEndhBuild函数构造 HList,例如:

hello = hEnd (hBuild 1 "2")
Run Code Online (Sandbox Code Playgroud)

映射print这个列表要困难得多。我认为没有简单的方法来编写能够映射printHList 的高阶函数,但您可以像这样手动遍历 HList:

{-# LANGUAGE DataKinds #-}

import Data.HList

class PrintEach ts where
  printEach :: HList ts -> IO ()
instance PrintEach '[] where
  printEach HNil = pure ()
instance (Show t, PrintEach ts) => PrintEach (t : ts) where
  printEach (HCons x xs) = print x *> printEach xs

hello = hEnd (hBuild 1 "2")

main = printEach hello
-- This prints:
-- 1
-- "2"
Run Code Online (Sandbox Code Playgroud)


lef*_*out 5

您可能不想只映射HList,而是要遍历它,即mapM. 而且您可能对个别结果不感兴趣(),而只对副作用感兴趣,所以就这样了mapM_

\n

HList 确实有一个通用工具,名为 毫不奇怪hMapM_。将它与任意约束多态函数一起使用有点复杂,但对于打印来说,它实际上是随库一起提供的,可供使用:

\n
Prelude Data.HList> let l = 1.*."2".*.HNil :: HList \'[Int, String]\nPrelude Data.HList> l\nH[1,"2"]\nPrelude Data.HList> hMapM_ HPrint l\n1\n"2"\n
Run Code Online (Sandbox Code Playgroud)\n

正如 Noughtmare 评论的那样,将其与其他多态函数一起使用(无需编写自定义类型)的方法是使用Fun,例如

\n
Prelude Data.HList> hMapM_ (Fun print :: Fun Show (IO ())) l\n1\n"2"\n
Run Code Online (Sandbox Code Playgroud)\n

……虽然不算尴尬,但还是有点烦人。我定义了一个同义词,允许使用 TypeApplications 编写此内容以避免冗余:

\n
{-# LANGUAGE TypeFamilies, RankNTypes, ConstraintKinds, UnicodeSyntax #-}\n\nimport Data.Kind\n\nfun :: \xe2\x88\x80 (cxt :: Type -> Constraint) getb\n        . (\xe2\x88\x80 a. (cxt a) => a -> getb) -> Fun cxt getb\nfun = Fun\n
Run Code Online (Sandbox Code Playgroud)\n

进而

\n
Prelude Data.HList Data.Kind> :set -XTypeApplications\nPrelude Data.HList Data.Kind> hMapM_ (fun @Show print) l\n1\n"2"\n
Run Code Online (Sandbox Code Playgroud)\n

或者我们甚至可以做到

\n
{-# LANGUAGE FlexibleContexts, AllowAmbiguousTypes #-}\n\nh\'MapM_ :: \xe2\x88\x80 (cxt :: Type -> Constraint) l m\n   . (Monad m, HFoldr (Mapcar (Fun cxt (m ()))) [m ()] l [m ()])\n    => (\xe2\x88\x80 a. (cxt a) => a -> m ()) -> HList l -> m ()\nh\'MapM_ f = hMapM_ (Fun f :: Fun cxt (m ()))\n
Run Code Online (Sandbox Code Playgroud)\n

进而

\n
Prelude Data.HList Data.Kind> h\'MapM_ @Show print l\n1\n"2"\n
Run Code Online (Sandbox Code Playgroud)\n