मैं जोएर्ड Visscher के जवाब पसंद है, लेकिन एक्सटेंशन - विशेष रूप से IncoherentInstances
, इस मामले में इस्तेमाल किया आंशिक आवेदन संभव बनाने के लिए - थोड़ा कठिन हो सकता है। यहां एक समाधान है जिसके लिए किसी भी एक्सटेंशन की आवश्यकता नहीं है।
सबसे पहले, हम कार्यों के डेटाटाइप को परिभाषित करते हैं जो जानते हैं कि किसी भी तर्क के साथ क्या करना है। आपको "रिटर्न टाइप" होने के रूप में "तर्क प्रकार" और b
होने के रूप में a
पढ़ना चाहिए।
data ListF a b = Cons b (ListF a (a -> b))
फिर हम कुछ (हास्केल) कार्यों को लिख सकते हैं जो इन (विविधता) कार्यों को व्यवस्थित करते हैं। मैं प्रीलूड में होने वाले किसी भी फ़ंक्शन के लिए F
प्रत्यय का उपयोग करता हूं।
headF :: ListF a b -> b
headF (Cons b _) = b
mapF :: (b -> c) -> ListF a b -> ListF a c
mapF f (Cons v fs) = Cons (f v) (mapF (f.) fs)
partialApply :: ListF a b -> [a] -> ListF a b
partialApply fs [] = fs
partialApply (Cons f fs) (x:xs) = partialApply (mapF ($x) fs) xs
apply :: ListF a b -> [a] -> b
apply f xs = headF (partialApply f xs)
उदाहरण के लिए, sum
समारोह एक variadic समारोह के रूप में के बारे में सोचा जा सकता है:
sumF :: Num a => ListF a a
sumF = Cons 0 (mapF (+) sumF)
sumExample = apply sumF [3, 4, 5]
हालांकि, हम भी सामान्य कार्यों, जो जरूरी नहीं जानते से निपटने के लिए सक्षम होना चाहते हैं क्या किसी भी तर्क के साथ करने के लिए। इसलिए क्या करना है? खैर, लिस्प की तरह, हम रनटाइम पर अपवाद फेंक सकते हैं। नीचे, हम f
का उपयोग गैर-वैरिएडिक फ़ंक्शन के एक साधारण उदाहरण के रूप में करेंगे।
f True True True = 32
f True True False = 67
f _ _ _ = 9
tooMany = error "too many arguments"
tooFew = error "too few arguments"
lift0 v = Cons v tooMany
lift1 f = Cons tooFew (lift0 f)
lift2 f = Cons tooFew (lift1 f)
lift3 f = Cons tooFew (lift2 f)
fF1 = lift3 f
fExample1 = apply fF1 [True, True, True]
fExample2 = apply fF1 [True, False]
fExample3 = apply (partialApply fF1 [True, False]) [False]
बेशक
, यदि आप अलग से lift0
, lift1
, lift2
, lift3
, आदि को परिभाषित करने के बॉयलरप्लेट पसंद नहीं है, तो आप कुछ एक्सटेंशन को सक्षम करने की जरूरत है। लेकिन आप उनके बिना काफी दूर हो सकते हैं!
यहां बताया गया है कि आप एक lift
फ़ंक्शन को सामान्यीकृत कैसे कर सकते हैं। सबसे पहले, हम कुछ मानक प्रकार-स्तर संख्याओं को परिभाषित करते हैं:
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FlexibleContexts, TypeFamilies, UndecidableInstances #-}
data Z = Z
newtype S n = S n
फिर उठाने के लिए टाइपक्लास प्रस्तुत करें। आपको I n a b
को a
की प्रतियों के रूप में b
"के रूप में पढ़ना चाहिए।
class Lift n a b where
type I n a b :: *
lift :: n -> I n a b -> ListF a b
instance Lift Z a b where
type I Z a b = b
lift _ b = Cons b tooMany
instance (Lift n a (a -> b), I n a (a -> b) ~ (a -> I n a b)) => Lift (S n) a b where
type I (S n) a b = a -> I n a b
lift (S n) f = Cons tooFew (lift n f)
और यहाँ पहले से f
, पुनः उपयोग द्वारा सामान्यीकृत लिफ्ट का उपयोग कर उदाहरण है: ठीक है, एक तरह से
fF2 = lift (S (S (S Z))) f
fExample4 = apply fF2 [True, True, True]
fExample5 = apply fF2 [True, False]
fExample6 = apply (partialApply fF2 [True, False]) [False]
यह समझने का एक तरीका है कि यह क्यों लागू होता है 'आवेदन' के लिए प्रकार हस्ताक्षर लिखने का प्रयास करना है। – augustss
यह भी देखें http://stackoverflow.com/questions/tagged/variadic-functions+haskell –
यह वास्तव में एक संभावित उपयोगी फ़ंक्शन का मेरा पसंदीदा उदाहरण है जो न तो गतिशील और निर्भर प्रकार वाले भाषा में लिखने के लिए अविश्वसनीय रूप से दर्दनाक है। सौभाग्य से यह अक्सर अभ्यास में नहीं आता है, क्योंकि अधिकांश वास्तविक उपयोग विभिन्न तरीकों से लिखे जा सकते हैं। –