2012-08-28 15 views
5

यह YAHT से व्यायाम करने के लिए मेरे समाधान है:क्या यह हैकेल नमूना छोटा हो सकता है?

व्यायाम 4.6 एक डेटाप्रकार टपल जो एक, दो, तीन या चार तत्वों पकड़ कर सकते हैं, निर्माता पर निर्भर करता है (लिखें कि है, वहाँ चार कंस्ट्रक्टर्स होना चाहिए , प्रत्येक तर्क के लिए एक)। फ़ंक्शन tuple1 को tuple4 के माध्यम से प्रदान करें जो एक ट्यूपल लेता है और उस स्थिति में केवल मान देता है, या कुछ भी वैध नहीं है (यानी आप टुपल 4 के लिए केवल दो तत्वों को पकड़ने के लिए पूछते हैं)।

जब मैं सही पहली पंक्ति मैं सादगी सी #

 

    data Tuplex a b c d = Tuple1 a | Tuple2 a b | Tuple3 a b c | Tuple4 a b c d 

    -- class Tuplex<a,b,c,d> { 
    --  Tuplex(a p1){ _p1 = p1; } 
    --  Tuplex(a p1, b p2){ _p1 = p1; _p2 = p2; } 
    --  Tuplex(a p1, b p2, c p3){ _p1 = p1; _p2 = p2; _p3 = p3; } 
    --  Tuplex(a p1, b p2, c p3, d p4){ _p1 = p1; _p2 = p2; _p3 = p3; _p4 = p4; } 
    --  public Nullable<a> _p1; 
    --  public Nullable<b> _p2; 
    --  public Nullable<c> _p3; 
    --  public Nullable<d> _p4; 
    -- } 

की तुलना में सी # मैं इस समस्या के बिना किसी भी क्षेत्र का उपयोग कर सकते में के बारे में उत्साहित थी लिखा था, लेकिन यहाँ मैं एक 'एक्सेसर कार्यों' लिखना चाहिए? और यहां कोड की मात्रा मुझे दुखी बनाती है।

क्या मेरे पास यहां छोटा कोड हो सकता है?

 

    tuple1 ∷ Tuplex a b c d → Maybe a 
    tuple2 ∷ Tuplex a b c d → Maybe b 
    tuple3 ∷ Tuplex a b c d → Maybe c 
    tuple4 ∷ Tuplex a b c d → Maybe d 
    tuple1 (Tuple1 a) = Just a 
    tuple1 (Tuple2 a b) = Just a 
    tuple1 (Tuple3 a b c) = Just a 
    tuple1 (Tuple4 a b c d) = Just a 
    tuple2 (Tuple1 a) = Nothing 
    tuple2 (Tuple2 a b) = Just b 
    tuple2 (Tuple3 a b c) = Just b 
    tuple2 (Tuple4 a b c d) = Just b 
    tuple3 (Tuple1 a) = Nothing 
    tuple3 (Tuple2 a b) = Nothing 
    tuple3 (Tuple3 a b c) = Just c 
    tuple3 (Tuple4 a b c d) = Just c 
    tuple4 (Tuple1 a) = Nothing 
    tuple4 (Tuple2 a b) = Nothing 
    tuple4 (Tuple3 a b c) = Nothing 
    tuple4 (Tuple4 a b c d) = Just d 

    -- unit tests 
    prop_tx1 = tuple1 (Tuple1 4) ≡ Just 4 
    prop_tx2 = tuple1 (Tuple2 4 'q') ≡ Just 4 
    prop_tx3 = tuple2 (Tuple1 4) ≡ (Nothing ∷ Maybe Char) 
    prop_tx4 = tuple2 (Tuple2 4 'q') ≡ Just 'q' 

+0

BTW सी # फायदे यहाँ से एक हो सकता है कि Nullable की तुलना में है। सी # में हमारे पास विशेष वाक्यविन्यास है (?पोस्टफिक्स) और पूरी तरह से पारदर्शी (लेकिन अभी भी वैकल्पिक रूप से नियंत्रित करने योग्य) टी के बीच रूपांतरण? और टी (int? और int)। अनबॉक्सिंग के दौरान भी, मैं ऑब्जेक्ट x = 5 कर सकता हूं; var y = (int?) x। Int बी = 5 से अनावश्यक रूपांतरण के बारे में उल्लेख नहीं है; int करने के लिए? सी = बी; –

+0

ओह, इतने सारे उत्तर और तरीके ... और आप जानते हैं क्या? अगर हम 1 9 डैनियल के जवाब को छोड़कर, उस अभ्यास बिंदु पर लेखक को उस मात्रा में ज्ञान प्रदान करते हैं, तो कुछ भी पर्याप्त नहीं है ... निश्चित रूप से, आगे पढ़ने से 'कहां' या '>> =' पर कुछ प्रकाश आ सकता है या '> =>' ऑपरेटर ... लेकिन मुझे यह जवाब काफी जटिल है, मुझे लगता है कि, मुझे लगता है कि मेरे द्वारा, मुश्किल लगता है :) बहुत जवाब के लिए धन्यवाद। –

उत्तर

7

यहां एक तरीका है: अपने पैटर्न मिलान को केंद्रीकृत करें।

{-# LANGUAGE NoMonomorphismRestriction #-} 
data DONE = DONE -- could just use(), but this is a pretty descriptive name 
type Tuplex a b c d = Maybe (a, Maybe (b, Maybe (c, Maybe (d, DONE)))) 

tuple1 x = x >>= return . fst -- or tuple1 = fmap fst 
tuple2 x = x >>= tuple1 . snd 
tuple3 x = x >>= tuple2 . snd 
tuple4 x = x >>= tuple3 . snd 
फिर

tuple1 है (दूसरों के बीच) प्रकार Tuplex a b c d -> Maybe a, और ऊपर tuple4 जो (फिर से, दूसरों के बीच) है प्रकार के पर:

unTuplex f1 f2 f3 f4 t = case t of 
    Tuple1 a  -> f1 a 
    Tuple2 a b  -> f2 a b 
    Tuple3 a b c -> f3 a b c 
    Tuple4 a b c d -> f4 a b c d 

tuple1 = unTuplex (\a -> Just a) (\a _ -> Just a) (\a _ _ -> Just a) (\a _ _ _ -> Just a) 
tuple2 = unTuplex (\_ -> Nothing) (\_ b -> Just b) (\_ b _ -> Just b) (\_ b _ _ -> Just b) 
tuple3 = unTuplex (\_ -> Nothing) (\_ _ -> Nothing) (\_ _ c -> Just c) (\_ _ c _ -> Just c) 
tuple4 = unTuplex (\_ -> Nothing) (\_ _ -> Nothing) (\_ _ _ -> Nothing) (\_ _ _ d -> Just d) 

वैकल्पिक रूप से, आप स्पष्ट रूप से आंतरिक संरचना व्यक्त कर सकते हैं Tuplex a b c d -> Maybe d

संपादित करें: ... वास्तव में, यह पहले दृष्टिकोण की वैकल्पिक निरंतरता का सुझाव देता है।

import Control.Monad 

decrement :: Tuplex a b c d -> Maybe (Tuplex b c d t) 
decrement (Tuple1 a) = Nothing 
decrement (Tuple2 a b) = Just (Tuple1 b) 
decrement (Tuple3 a b c) = Just (Tuple2 b c) 
decrement (Tuple4 a b c d) = Just (Tuple3 b c d) 

zero :: Tuplex a b c d -> a 
zero (Tuple1 a) = a 
zero (Tuple2 a b) = a 
zero (Tuple3 a b c) = a 
zero (Tuple4 a b c d) = a 

tuple1 = Just . zero 
tuple2 = decrement >=> tuple1 
tuple3 = decrement >=> tuple2 
tuple4 = decrement >=> tuple3 
1

बस अपने टुपल्स फ़ील्ड नाम दें!

data Tuplex a b c d = Tuple1 { tuple1 :: a } 
        | Tuple2 { tuple1 :: a 
          , tuple2 :: b } 
        | Tuple3 { tuple1 :: a 
          , tuple2 :: b 
          , tuple3 :: c } 
        | Tuple4 { tuple1 :: a 
          , tuple2 :: b 
          , tuple3 :: c 
          , tuple4 :: d } 

और एक परिणाम के रूप में आप के प्रकार के साथ कार्य करना:

tuple1 :: Tuplex a b c d -> a 
tuple2 :: Tuplex a b c d -> b 
-- etc 

इस तरह अभिलेखों का उपयोग करना फ़ील्ड नाम वास्तव में पैटर्न मिलान सहजता की वजह से कम आम की तुलना में आप हास्केल में उम्मीद कर सकते हैं और , कम से कम कुछ हलकों में, RecordWildCard विस्तार की लोकप्रियता है जो आप की तरह काम करने के लिए अनुमति देता है:

function (Tuples3 {..}) = 
-- now you have variables tuple1 :: a, tuple2 :: b, etc. 

(जब रिकॉर्ड वाइल्ड कार्ड का उपयोग कर इसे bett हो सकता है अपने tuple फ़ील्ड को कुछ आसान बनाने के लिए, जैसे tupA, tupB, tupc, tupD)

+7

दूसरी समस्या, कम से कम इस उदाहरण में, यह है कि एक्सेसर फ़ंक्शंस आंशिक हैं। कुछ 'tuple2 (Tuple1 "foo") की तरह कुछ तोड़ देगा। इस विशेष मामले में - और सबसे सामान्य कोड में, मुझे कल्पना है - आप इस तरह की अमान्य पहुंच को संभालने के लिए कुछ और शानदार तरीका चाहते हैं (उदाहरण के लिए प्रश्न में निर्दिष्ट 'हो सकता है' वापस लौटना)। –

+0

आह, मैंने नहीं देखा कि उसने 'शायद' इस्तेमाल किया था। 'Derive' टूल शायद ऐसा कर सकता है और यदि नहीं तो इसे पैच किया जाना चाहिए। इसके अलावा, उनके उपयोग में थोड़ा अंतर है और 'डेटा टुप abcd = tup {tA :: (शायद ए), टीबी :: (शायद बी) ...} '(साथ ही कुछ सहायक फ़ंक्शन/कन्स्ट्रक्टर) तो शायद यह होगा एक बेहतर समाधान। –

1
import Safe (atMay) -- from the 'safe' package 

toList (Tuple1 a) = [a] 
toList (Tuple2 a b) = [a, b] 
toList (Tuple3 a b c) = [a, b, c] 
toList (Tuple4 a b c d) = [a, b, c, d] 

tuple n t = atMay (toList t) n 

[tuple1, tuple2, tuple3, tuple4] = map tuple [1..4] 

संपादित करें: वाइटस सही ढंग से बताते हैं कि एक सजातीय टपल के लिए यह केवल काम करता है, तो यह एक सही जवाब नहीं है। उस मामले में मैं डैनियल के जवाब को रोकता हूं।

+1

यदि आप किसी भी कारण से बाहरी पैकेज का उपयोग नहीं करना चाहते हैं, तो आप 'listToMaybe' जैसी कुछ भी कर सकते हैं। ड्रॉप एन'। –

+1

यह केवल तभी काम करता है जब सभी ट्यूपल तत्वों का एक ही प्रकार हो। – Landei

+1

आपको लगता है कि 'tuple1 :: TupleX a a a -> शायद a' और अधिक सामान्य नहीं' TupleX a b c d -> शायद a'। – Vitus

7

मैं इसे मृत सरल रखने की कोशिश करेंगे:

data Tuplex a b c d = Tuple1 a | Tuple2 a b | Tuple3 a b c | Tuple4 a b c d 

toMaybes (Tuple1 p)  = (Just p, Nothing, Nothing, Nothing) 
toMaybes (Tuple2 p q)  = (Just p, Just q, Nothing, Nothing) 
toMaybes (Tuple3 p q r) = (Just p, Just q, Just r, Nothing) 
toMaybes (Tuple4 p q r s) = (Just p, Just q, Just r, Just s) 

tuple1 t = p where (p,_,_,_) = toMaybes t 
tuple2 t = q where (_,q,_,_) = toMaybes t 
tuple3 t = r where (_,_,r,_) = toMaybes t 
tuple4 t = s where (_,_,_,s) = toMaybes t 
+0

यह आसान और समझा जा सकता है लेकिन इस पुस्तक को पढ़ने के बिंदु पर मैं 'कहां' ऑपरेटर –

+0

से अपरिचित हूं, यह 'tuple1 t = let (p, _, _, _) = pay में maybes t के समान है। ज्यादातर मामलों में आप 'कहां' एक प्रकार के "उल्टा 'चलो' के रूप में देख सकते हैं। हालांकि, scopes आदि के बारे में कुछ मतभेद हैं। – Landei

संबंधित मुद्दे