通常的異構名單可以在這裏使用:
{-# LANGUAGE
UndecidableInstances, GADTs,
TypeFamilies, MultiParamTypeClasses,
FunctionalDependencies, DataKinds, TypeOperators,
FlexibleInstances #-}
import Control.Applicative
data HList xs where
Nil :: HList '[]
(:>) :: x -> HList xs -> HList (x ': xs)
infixr 5 :>
-- A Show instance, for illustrative purposes here.
instance Show (HList '[]) where
show _ = "Nil"
instance (Show x, Show (HList xs)) => Show (HList (x ': xs)) where
show (x :> xs) = show x ++ " : " ++ show xs
我們平時寫HLists
類的使用功能,用一個實例Nil
,另一個用於:>
情況。但是,它不會是非常有類只是一個單一的使用情況下(即笛卡爾積在這裏),所以讓我們推廣的問題,以應用性排序:
class Applicative f => HSequence f (xs :: [*]) (ys :: [*]) | xs -> ys, ys f -> xs where
hsequence :: HList xs -> f (HList ys)
instance Applicative f => HSequence f '[] '[] where
hsequence = pure
instance (Applicative g, HSequence f xs ys, y ~ x, f ~ g) =>
HSequence g (f x ': xs) (y ': ys) where
hsequence (fx :> fxs) = (:>) <$> fx <*> hsequence fxs
注意,在該實例中使用的~
限制定義。它極大地幫助類型推理(以及類聲明中的函數依賴關係);總體思路是將盡可能多的信息從實例頭部移動到約束條件,因爲這可以讓GHC延遲解決它們,直到有足夠的上下文信息。
現在笛卡爾產品開箱的:
> hsequence ([1, 2] :> "ab" :> Nil)
[1 : 'a' : Nil,1 : 'b' : Nil,2 : 'a' : Nil,2 : 'b' : Nil]
而且我們還可以使用hsequence
任何Applicative
:
> hsequence (Just "foo" :> Just() :> Just 10 :> Nil)
Just "foo" :() : 10 : Nil
編輯:我發現(感謝dfeuer)是相同的功能可從現有的hlist
包裝中獲得:
import Data.HList.CommonMain
> hSequence ([3, 4] .*. "abc" .*. HNil)
[H[3, 'a'],H[3, 'b'],H[3, 'c'],H[4, 'a'],H[4, 'b'],H[4, 'c']]
@chi真的嗎?在我的解釋中,他要求組合,而不是拉鍊;即「liftA2(,)」等(用於列表)。 – phg 2015-03-03 13:56:21
@phb你說得對。不過,如果我們可以使用嵌套對而不是元組,我們可以通過類型類和'liftA2(,)'來解決這個問題。使用元組很難,因爲沒有方便的方法從n元組移動到n + 1元組。 – chi 2015-03-03 14:11:06
有趣的事實:GHC不支持超過62個元素的元組:https://downloads.haskell.org/~ghc/latest/docs/html/libraries/ghc-prim-0.3.1.0/src/GHC-Tuple。 HTML。所以肯定有一種方法可以手動實現所有'cartProdN'變體,最多62個;)。這就是說,你是否真的需要任意的笛卡爾產品? ''zipWith *'及其變種可能會停在'7'處,這可能是有原因的...... – Zeta 2015-03-03 14:18:35