2015-03-03 15 views
6

में कार्टेशियन उत्पाद मुझे पता है कि 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')] समस्या को संभालना चाहिए, और प्रत्येक सूची का प्रकार अलग है और न ही बाहरी ट्यूपल के प्रकार (आकार) के बारे में ध्यान रखना चाहिए। ([a1], [a2], [a3] ...) -> [(a1, a2, a3 ...)]

मैं जानता हूँ कि वहाँ प्रकार प्रणाली के साथ यहाँ कुछ समस्या है:

तो, cartProd समारोह मैं चाहता हूँ इस तरह की एक प्रकार है। लेकिन क्या इस cartProd के एक परिपूर्ण संस्करण को लागू करने का कोई तरीका है? Nil और एक अन्य :> मामले के लिए के लिए

{-# 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 वर्गों के प्रयोग पर काम करता है लिखते हैं, एक उदाहरण के साथ:

+0

@chi वास्तव में? मेरी व्याख्या में, वह संयोजनों के लिए पूछता है, ज़िप नहीं; यानी, लिफ्टए 2 (,) 'और इसी तरह (सूचियों के लिए)। – phg

+0

@phb आप सही हैं।फिर भी, अगर हम tuples के बजाय नेस्टेड जोड़े का उपयोग कर सकते हैं तो हम इसे एक प्रकार के वर्ग और 'liftA2 (,)' के माध्यम से हल करने में सक्षम होंगे, जैसा कि आप प्रस्तावित करते हैं। Tuples के साथ यह कठिन है क्योंकि एन-टुपल से एन + 1-टुपल तक जाने का कोई आसान तरीका नहीं है। – chi

+1

मजेदार तथ्य: जीएचसी 62 प्रविष्टियों से अधिक लंबे समय तक tuples का समर्थन नहीं करता है: https://downloads.haskell.org/~ghc/latest/docs/html/libraries/ghc-prim-0.3.1.0/src/GHC-Tuple। एचटीएमएल। इसलिए हाथ से 62 तक सभी 'कार्टप्रोडन' प्रकारों को लागू करने का निश्चित रूप से एक तरीका है;)। ऐसा कहा जा रहा है, क्या आपको _really_ मनमानी कार्टेशियन उत्पादों की आवश्यकता है? संभवतः एक कारण है कि 'ज़िप * * और इसके रूपों को '7' पर रोक दिया गया है ... – Zeta

उत्तर

4

सामान्य विषम सूची यहां इस्तेमाल किया जा सकता है। हालांकि, यह बस एक ही उपयोग के मामले (अर्थात् कार्तीय उत्पादों यहाँ) के लिए एक वर्ग के लिए सुंदर नहीं होगा, तो चलो अनुप्रयोगी अनुक्रमण के लिए समस्या सामान्यीकरण करते हैं:

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 ([1, 2] :> "ab" :> Nil) 
[1 : 'a' : Nil,1 : 'b' : Nil,2 : 'a' : Nil,2 : 'b' : Nil] 

और हम भी किसी भी Applicative साथ hsequence उपयोग कर सकते हैं:

> 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']] 
+0

मुझे लगता है कि' एचएलआईटी' पैकेज पहले से ही ऐसा कुछ ऑफर कर सकता है, लेकिन मुझे यकीन नहीं है कि यह काफी समान है। यह एक संबंधित ट्यूपल प्रकार के साथ 'एचएलआईस्ट की टुपल्स को परिवर्तित करने के लिए एक वर्ग लिखने (या उल्लेख, यदि यह पहले से मौजूद है) को समझने का अर्थ हो सकता है। – dfeuer

+0

@dfeuer: मैंने इसे 'hlist' में पाया और यह वही है (संपादन देखें)। –

2

टेम्पलेट हास्केल का उपयोग करना इसे हासिल करना संभव है।

{-# 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] 

तो शायद उपयोग करने के लिए थोड़ा अजीब है, लेकिन है कि किसी भी tuples समर्थन की कीमत है:

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')] 
0

मैं एक बेहतर समाधान अपने आप को पाया, इस समाधान उपयोगकर्ता के लिए एकदम सही है, लेकिन यह कार्यान्वयन प्रकार है बदसूरत के (हर टपल के कहने बनाना चाहिए, बस जिप की तरह):

{-# 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']) 

हम भी जिप का एक बेहतर संस्करण, इस तरह से प्रदान कर सकते हैं, इसलिए है कि हम एक ही समारोह नाम का उपयोग कर सकते zip' बजाय zip, zip3, zip4 ...:

{-# 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']) 
संबंधित मुद्दे