Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Haskell中计算N元(不同类型!!)笛卡尔积_Haskell_Cartesian Product_Template Haskell - Fatal编程技术网

在Haskell中计算N元(不同类型!!)笛卡尔积

在Haskell中计算N元(不同类型!!)笛卡尔积,haskell,cartesian-product,template-haskell,Haskell,Cartesian Product,Template Haskell,我知道函数sequence可以处理[[1,2],[3,4]]->[[1,3],[1,4],[2,3],[2,4]]问题 但我认为真正的笛卡尔积应该处理([1,2],'a','b'])->[(1,a'),(1,b'),(2,a'),(2,b')]问题,并且应该关心每个列表的类型是否不同,外部元组的类型是否不同(&size) 因此,我想要的cartProd函数的类型如下:([a1]、[a2]、[a3]…)->[(a1、a2、a3…) 我知道类型系统有一些问题。但是有什么方法可以实现这个cartPro

我知道函数
sequence
可以处理
[[1,2],[3,4]]->[[1,3],[1,4],[2,3],[2,4]]
问题

但我认为真正的笛卡尔积应该处理
([1,2],'a','b'])->[(1,a'),(1,b'),(2,a'),(2,b')]
问题,并且应该关心每个列表的类型是否不同,外部元组的类型是否不同(&size)

因此,我想要的
cartProd
函数的类型如下:
([a1]、[a2]、[a3]…)->[(a1、a2、a3…)


我知道类型系统有一些问题。但是有什么方法可以实现这个
cartProd
的完美版本吗?

这里可以使用通常的异构列表:

{-# 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
我们还可以将
hsequence
与任何
应用程序一起使用:

> hsequence (Just "foo" :> Just () :> Just 10 :> Nil)
Just "foo" : () : 10 : Nil
编辑:我发现(感谢dfeuer)现有软件包也提供了相同的功能:


使用模板Haskell可以实现这一点

{-# LANGUAGE TemplateHaskell #-}
f :: ExpQ -> ExpQ
f ess = do es <- ess
           case es of
             (TupE e) -> return $ h e
             _ -> fail "f expects tuple of lists"
  where
    h ts = let ns = zipWith (\_ -> mkName . ('x':) . show) ts [0..]
           in CompE $ (zipWith (BindS . VarP) ns ts) ++
                      [NoBindS $ TupE $ map VarE ns]

我自己找到了一个更好的解决方案,这个解决方案非常适合用户,但它的实现有点难看(必须创建每个元组的实例,就像zip一样):


@真的吗?在我的理解中,他要求的是组合,而不是拉链;i、 例如,
liftA2(,)
等等(对于列表)。@phb你说得对。尽管如此,如果我们可以使用嵌套对而不是元组,我们将能够通过类型类和
liftA2(,)
,如您所建议的,来解决这个问题。有了元组,就更难了,因为没有方便的方法从n元组移动到n+1元组。有趣的事实:GHC不支持长度超过62个条目的元组:。因此,肯定有一种方法可以实现所有
cartProdN
变体,最多可手动实现62个;)。也就是说,你真的需要任意的笛卡尔积吗?可能是有原因的
zipWith*
及其变体停在
7
…我认为
HList
包可能已经提供了类似的功能,但我不确定它是否完全相同。编写(或提及,如果它已经存在的话)一个类来将
HList
s转换为元组,并具有相关的元组类型,这可能也有意义。@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']]
{-# LANGUAGE TemplateHaskell #-}
f :: ExpQ -> ExpQ
f ess = do es <- ess
           case es of
             (TupE e) -> return $ h e
             _ -> fail "f expects tuple of lists"
  where
    h ts = let ns = zipWith (\_ -> mkName . ('x':) . show) ts [0..]
           in CompE $ (zipWith (BindS . VarP) ns ts) ++
                      [NoBindS $ TupE $ map VarE ns]
Prelude> take 7 $ $(f [| ([1..], [1..2], "ab") |] )
[(1,1,'a'),(1,1,'b'),(1,2,'a'),(1,2,'b'),(2,1,'a'),(2,1,'b'),(2,2,'a')]
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FunctionalDependencies #-}

class CartProd a b | a -> b where
    cartProd :: a -> b

instance CartProd ([a], [b]) [(a, b)] where
    cartProd (as, bs) = [(a, b) | a <- as, b <- bs]

instance CartProd ([a], [b], [c]) [(a, b, c)] where
    cartProd (as, bs, cs) = [(a, b, c) | a <- as, b <- bs, c <- cs]

c = cartProd (['a'..'c'], [0..2])
d = cartProd (['a'..'c'], [0..2], ['x'..'z'])
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FunctionalDependencies #-}

class Zip a b | a -> b where
    zip' :: a -> b

instance Zip ([a], [b]) [(a, b)] where
    zip' (as, bs) = zip as bs

instance Zip ([a], [b], [c]) [(a, b, c)] where
    zip' (as, bs, cs) = zip3 as bs cs

a = zip' (['a'..'z'], [0..])
b = zip' (['a'..'z'], [0..], ['x'..'z'])