2012-10-12 33 views
9

मैं एक ऐसा फ़ंक्शन लिख रहा हूं जो कुछ मनमाने ढंग से प्रतीकों के अनुक्रम में खोज करता है। मैं इसे सामान्य जेनेरिक बनाना चाहता हूं ताकि यह सूचियों पर काम करे, Foldable एस ByteString एस और Text एस पर भी काम करता है। इसे Foldable पर सामान्य बनाना सरल है। लेकिन ByteString एस और Text एस कैसे शामिल करें? निश्चित रूप से मैं ByteString को एक सूची में परिवर्तित कर सकता हूं और फिर मेरे फ़ंक्शन को कॉल कर सकता हूं, लेकिन मैं सभी फायदे ByteString एस खो दूंगा। ,सूचियों, बाइटस्ट्रिंग्स और ग्रंथों (और शायद अन्य समान प्रतिनिधित्व) पर एक एकल फ़ंक्शन काम करना

import Control.Monad.State 
import qualified Data.Foldable as F 
import Data.Map.Strict (Map) 
import qualified Data.Map.Strict as Map 
import Data.Word 
import qualified Data.ByteString as B 
import qualified Data.Text as T 

type Histogram a = Map a Int 

empty :: (Ord a) => Histogram a 
empty = Map.empty 

histogramStep :: (Ord a) => a -> Histogram a -> Histogram a 
histogramStep k = Map.insertWith (+) k 1 

histogram :: (Ord a, F.Foldable t) => t a -> Histogram a 
histogram = F.foldl (flip histogramStep) empty 

लेकिन चूंकि न ByteString और न ही पाठ Foldable हो सकता है (यह भंडार सिर्फ Word8 एस/Char रों, नहीं मनमाना तत्व):

एक ठोस उदाहरण के लिए, हम एक हिस्टोग्राम समारोह बनाना चाहते जाने करवाने के लिए मैं और अधिक कार्यों है कि एक तरह से पहले देखो बिल्कुल बनाने के साथ फंस कर रहा हूँ, बस एक अलग प्रकार हस्ताक्षरों के साथ:

histogramBS :: B.ByteString -> Histogram Word8 
histogramBS = B.foldl (flip histogramStep) empty 

histogramText :: T.Text -> Histogram Char 
histogramText = T.foldl (flip histogramStep) empty 

यह कुछ ऐसा है जो हास्केल जैसी कार्यात्मक भाषा में अपेक्षा नहीं करता है।

इसे एक बार और सभी के लिए histogram लिखने के लिए सामान्य कैसे बनाएं?

+2

क्योंकि आप आप क्या कर रहे हैं गहराई से लगता है कि तुम हमेशा दिलचस्प सवाल पूछने और हमेशा अधिक जानना चाहते हैं। +1 – AndrewC

उत्तर

9

आपका समाधान बहुत अधिक है ListLike पैकेज करता है। अतिरिक्त पैकेज listlike-instances भी है जो Text और Vector के लिए उदाहरण जोड़ता है।

+0

यह भी देखें http://hackage.haskell.org/package/stringable – nponeccop

5

थोड़ी देर के बाद मैंने स्वयं को हल किया, लेकिन मुझे यकीन नहीं है कि इसे बेहतर तरीके से हल किया जा सकता है, या अगर किसी ने पहले से ही कुछ लाइब्रेरी में ऐसा किया है।

newtype WrapFoldable f a = WrapFoldable { unwrapFoldable :: f a } 
instance (F.Foldable f) => Foldable' (WrapFoldable f a) where 
    type Element (WrapFoldable f a) = a 
    foldlE f z = F.foldl f z . unwrapFoldable 

instance Foldable' B.ByteString where 
    type Element B.ByteString = Word8 
    foldlE = B.foldl 


instance Foldable' T.Text where 
    type Element (T.Text) = Char 
    foldlE = T.foldl 

या और भी बेहतर FlexibleInstances साथ:

instance (F.Foldable t) => Foldable' (t a) where 
    type Element (t a) = a 
    foldlE = F.foldl 

अब मैं लिख सकते हैं (FlexibleContexts साथ

मैं एक प्रकार स्तरीय TypeFamilies साथ

class Foldable' t where 
    type Element t :: * 
    foldlE :: (b -> Element t -> b) -> b -> t -> b 
    -- other functions could be copied here from Foldable 

और उदाहरणों के रूप में बनाया):

histogram :: (Ord (Element t), Foldable' t) => t -> Histogram (Element t) 
histogram = foldlE (flip histogramStep) empty 

और Foldable रों, ByteString है, पर इसका इस्तेमाल Text रों आदि

  • एक और (शायद आसान) जिस तरह से यह करने के लिए है?
  • क्या कोई ऐसी लाइब्रेरी है जो इस समस्या को हल करती है (इस तरह या किसी अन्य में)?
5

आप objectifying पर विचार हो सकता खुद को फोल्ड:

{-# LANGUAGE GADTs #-} 
import Data.List (foldl', unfoldr) 
import qualified Data.ByteString.Lazy as B 
import qualified Data.Vector.Unboxed as V 
import qualified Data.Text as T 
import qualified Data.Map as Map 
import Data.Word 
type Histogram a = Map.Map a Int 

empty :: (Ord a) => Histogram a 
empty = Map.empty 
histogramStep :: (Ord a) => Histogram a -> a -> Histogram a 
histogramStep h k = Map.insertWith (+) k 1 h 

histogram :: Ord b => Fold b (Histogram b) 
histogram = Fold histogramStep empty id 

histogramT :: T.Text -> Histogram Char 
histogramT = foldT histogram 
histogramB :: B.ByteString -> Histogram Word8 
histogramB = foldB histogram 
histogramL :: Ord b => [b] -> Histogram b 
histogramL = foldL histogram 

-- helper library 
-- see http://squing.blogspot.fr/2008/11/beautiful-folding.html 
-- note existential type 
data Fold b c where Fold :: (a -> b -> a) -> !a -> (a -> c) -> Fold b c 
instance Functor (Fold b) where fmap f (Fold op x g) = Fold op x (f . g) 

foldL :: Fold b c -> [b] -> c 
foldL (Fold f x c) bs = c $ (foldl' f x bs) 

foldV :: V.Unbox b => Fold b c -> V.Vector b -> c 
foldV (Fold f x c) bs = c $ (V.foldl' f x bs) 

foldT :: Fold Char t -> T.Text -> t 
foldT (Fold f x c) t = c $ (T.foldl' f x t) 

foldB :: Fold Word8 t -> B.ByteString -> t 
foldB (Fold f x c) t = c $ (B.foldl' f x t) 


sum_, product_ :: Num a => Fold a a 
sum_ = Fold (+) 0 id 
product_ = Fold (*) 1 id 

length_ :: Fold a Int 
length_ = Fold (const . (+1)) 0 id 
maximum_ = Fold max 0 id 
+0

हालांकि यह संभवतः जिस तरह से मैं जाऊंगा, यह बहुत दिलचस्प है। निश्चित रूप से यह खोज के लायक है। मुझे यह भी विश्वास है कि 'फोल्ड' एक कॉमोनैड है:' उदाहरण कॉमोनैड (फोल्ड बी) जहां निकालें (फोल्ड _ एक्स आर) = आर एक्स; डुप्लिकेट (फोल्ड एफ एक्स आर) = फोल्ड एफ एक्स (\ y -> फोल्ड एफ वाई आर) ', मैंने संक्षेप में कानूनों की जांच की और वैध प्रतीत होता है। इससे अपने परिचालन को गठबंधन करने के तरीके और तरीके मिल सकते हैं। –

+0

दिलचस्प; यह निश्चित रूप से आवेदक है - यह टिप्पणी में उल्लेख किया गया है, यह चर्चा करने में रबकिन का उद्देश्य था। मैं महान कोनल इलियट द्वारा कई पदों का उल्लेख करना भूल गया। http://conal.net/blog/posts/proofs-for-left-fold-zipping, रबकिन के बाद, जिसे मैंने पूरी तरह से पढ़ा नहीं है। वह और रबकिन इस मुद्दे पर बहुत अधिक तथ्य नहीं लग रहे हैं, कि 'फोल्ड' प्रकार में सूचियों के साथ विशेष रूप से कुछ भी नहीं है, लेकिन सामान्य 'फ़ोल्डएक्स' फ़ंक्शन दिए गए किसी भी धारावाहिक प्रकार एक्स पर लागू किया जा सकता है। मैंने पहली बार इसके बारे में 'sdcvvc' की टिप्पणी से सीखा http://stackoverflow.com/questions/10803221 – applicative

2

मैं lens पैकेज है, जो एक विस्तृत प्रकार स्तरीय पदानुक्रम डेटा संरचनाओं के विभिन्न प्रकार की पहचान है का उपयोग करते हुए एक और समाधान मिल गया। इसका दृष्टिकोण अनुप्रयोगी के जवाब में एक के समान है - यह सिलवटों objectifies:

{-# LANGUAGE RankNTypes #-} 
import Control.Monad.State 
import qualified Data.Foldable as F 
import Data.Map.Strict (Map) 
import qualified Data.Map.Strict as Map 
import Data.Word 
import qualified Data.ByteString as B 
import qualified Data.Text as T 

import Control.Lens.Fold 
import qualified Data.ByteString.Lens as LBS 
import qualified Data.Text.Lens as LT 

type Histogram a = Map a Int 

empty :: (Ord a) => Histogram a 
empty = Map.empty 

histogramStep :: (Ord a) => a -> Histogram a -> Histogram a 
histogramStep k = Map.insertWith (+) k 1 

-- Histogram on anything that can be folded into `a`: 

histogram :: (Ord a) => Fold c a -> c -> Histogram a 
histogram f = foldlOf f (flip histogramStep) empty 

-- Specializations are simple: 

histogramF :: (Ord a, F.Foldable t) => t a -> Histogram a 
histogramF = histogram folded 

histogramBS :: B.ByteString -> Histogram Word8 
histogramBS = histogram LBS.bytes 

histogramText :: T.Text -> Histogram Char 
histogramText = histogram LT.text