2013-06-17 2 views
5

से निपट नहीं सकता हूं, मैं एक हास्केल फ़ंक्शन लिखना चाहता हूं जो फ्लिप की तरह कार्य करता है लेकिन कहीं अधिक सामान्य है और फ़ंक्शन का कोई पैरामीटर अंतिम पैरामीटर बन सकता है। सुविधा के लिए, हम इसका प्रतिनिधित्व करने के लिए pull का उपयोग करते हैं।मैं एक समारोह लिखना चाहता हूं जो लैम्ब्डा अभिव्यक्तियों से छुटकारा पाने के लिए हास्केल में 'फ्लिप' जैसा है। लेकिन मैं इसके प्रकार

यह निम्न कोड लिखने के लिए आसान है:

Prelude> :t flip   --we just call this function a swap 
flip :: (a -> b -> c) -> b -> a -> c 
Prelude> :t (flip.)  --we just call this function a swap 
(flip.) :: (a -> a1 -> b -> c) -> a -> b -> a1 -> c 
Prelude> :t ((flip.).) --we just call this function a swap 
((flip.).) :: (a -> a1 -> a2 -> b -> c) -> a -> a1 -> b -> a2 -> c 
Prelude> :t (((flip.).).) --we just call this function a swap 
(((flip.).).) 
    :: (a -> a1 -> a2 -> a3 -> b -> c) -> a -> a1 -> a2 -> b -> a3 -> c 

और हम पाते हैं कि के साथ और अधिक फ्लिप करने के लिए लागू है, यह मापदंडों के मनमाने ढंग से सटे जोड़ी स्वैप कर सकते हैं (।)। और इसके बाद के संस्करण परिणामों के साथ हम लिख सकते हैं:

Prelude> :t flip 
flip :: (a -> b -> c) -> b -> a -> c 
Prelude> :t (flip.) . flip 
(flip.) . flip :: (a1 -> a -> b -> c) -> a -> b -> a1 -> c 
Prelude> :t ((flip.).) . (flip.) . flip 
((flip.).) . (flip.) . flip 
    :: (a2 -> a -> a1 -> b -> c) -> a -> a1 -> b -> a2 -> c 
Prelude> :t (((flip.).).) . ((flip.).) . (flip.) . flip 
(((flip.).).) . ((flip.).) . (flip.) . flip 
    :: (a3 -> a -> a1 -> a2 -> b -> c) -> a -> a1 -> a2 -> b -> a3 -> c 

हम पा सकते हैं कि और अधिक स्वैप के साथ बना है, यह अंतिम स्थान पर एक मनमाना पैरामीटर खींच सकते हैं। तो हम कई मामलों में लैम्ब्डा अभिव्यक्ति से छुटकारा पा सकते हैं। लेकिन उपर्युक्त एक्सप्रेस बहुत फूला हुआ है।

मेरा मुख्य विचार उपर्युक्त कार्यों को सामान्यीकृत करने के लिए pull फ़ंक्शन बनाना है। pull लगभग मोटे तौर पर कार्य करता है।

let f = undefined    --For convenience, we let f be undefined. 

:t pull 0 (f::a->b->z)   --the type variable z is not a function type. 
>pull 0 (f::a->b->z) :: b->a->z --pull is just like flip for 0 and a function of this type. 
:t pull 0 (f::a->b->c->z)  --the type variable z is not a function type. 
>pull 0 (f::a->b->c->z) :: b->c->a->z 

:t pull 1 (f::a->b->c->z)  --the type variable z is not a function type. 
>pull 1 (f::a->b->c->z) :: a->c->b->z 
:t pull 1 (f::a->b->c->d->z) --the type variable z is not a function type. 
>pull 1 (f::a->b->c->d->z) :: a->c->d->b->z 

:t pull 2 (f::a->b->c->d->z) --the type variable z is not a function type. 
>pull 2 (f::a->b->c->d->z) :: a->b->d->c->z 
:t pull 2 (f::a->b->c->d->e->z) --the type variable z is not a function type. 
>pull 2 (f::a->b->c->d->e->z) :: a->b->d->e->c->z 

मैंने ऐसा करने के कई तरीकों की कोशिश की। naivest एक है:

swap :: Word -> a -> a 
swap 0 = flip 
swap n = dot $ swap (n-1) 

और GHC bellow तरह शिकायत की और मुझे समझ में क्यों:

-- Prelude> :reload 
-- [1 of 1] Compiling Main    (ModifyArbitrayParameterOfAFunction.hs, interpreted) 
-- 
-- ModifyArbitrayParameterOfAFunction.hs:4:21: 
--  Occurs check: cannot construct the infinite type: c0 = a1 -> c0 
--  Expected type: (a1 -> c0) -> c0 
--  Actual type: (a1 -> c0) -> a1 -> c0 
--  In the return type of a call of `modify' 
--  Probable cause: `modify' is applied to too few arguments 
--  In the first argument of `(.)', namely `(modify (n - 1) modi)' 
--  In the expression: (modify (n - 1) modi) . f1 
-- 
-- ModifyArbitrayParameterOfAFunction.hs:4:42: 
--  Occurs check: cannot construct the infinite type: c0 = a1 -> c0 
--  Expected type: a1 -> a1 -> c0 
--  Actual type: a1 -> c0 
--  In the second argument of `(.)', namely `f1' 
--  In the expression: (modify (n - 1) modi) . f1 
--  In an equation for `modify': 
--   modify n modi f1 = (modify (n - 1) modi) . f1 
-- Failed, modules loaded: none. 

हो सकता है कि मेरा लक्ष्य सिर्फ एक इच्छाधारी सोच है, लेकिन हास्केल के प्रकार प्रणाली पर विचार भी लैम्ब्डा भाव लिखने में सक्षम है , मुझे यह कहने की हिम्मत है कि ऐसा करने का एक तरीका होना चाहिए।

+1

मुझे लगता है कि यह संभव है, लेकिन निश्चित रूप से कुछ हल्के ओलेगरी की आवश्यकता होगी। – Artyom

+2

आपके द्वारा वर्णित तरीके से संभव नहीं है। बस क्योंकि रनटाइम पर खींचने के लिए पैरामीटर मान (जो उपलब्ध है) पुल के प्रकार का निर्धारण नहीं कर सकता है (जो संकलन समय पर आवश्यक है) – Ankur

+0

लेकिन, मुझे लगता है कि पुल पैरामीटर फ़ंक्शन पर उचित प्रकार का आधार चुन सकता है, केवल तभी पैरामीटर फ़ंक्शन की पहचान करने का एक तरीका एक यूनरी फ़ंक्शन है, दो चर के फ़ंक्शन या कई चर के फ़ंक्शन – TorosFanny

उत्तर

1

जैसा कि टिप्पणियों में उल्लिखित है, आप एक ऐसा कार्य नहीं कर सकते जिसके लिए आप उस फ़ंक्शन की धैर्य को पारित कर सकें जिसे आप फ़्लिप करना चाहते हैं। पैरामीटर को रनटाइम पर गणना की जाती है, जबकि आपको संकलन समय पर मान की आवश्यकता होती है ताकि आप सही प्रकार निर्धारित कर सकें।

न तो आप इसे किसी भी तरह से धैर्य के बिना बना सकते हैं। उदाहरण के लिए a -> b -> c -> dd लौटने वाले तीन तर्कों के फ़ंक्शन के रूप में देखा जा सकता है, या यदि दो तर्क c -> d लौटते हैं तो फ़ंक्शन के रूप में देखा जा सकता है।

शायद सबसे आसान समाधान स्पष्ट रूप से कार्यों को परिभाषित करना होगा, जैसे कि flip2, flip3 आदि। मुझे पता है कि यह वह नहीं है जिसे आप ढूंढ रहे हैं, लेकिन यह सबसे व्यावहारिक समाधान है।

एक और विकल्प टेम्पलेट हास्केल का उपयोग करना होगा। फिर, स्थिति अलग है, क्योंकि टेम्पलेट हास्केल निष्पादित करता है (मैं संकलन समय पर "मेटा-") कोड कहूंगा। TH के साथ आप एक ऐसा फ़ंक्शन बना सकते हैं जो प्राकृतिक संख्या लेता है और एक TH अभिव्यक्ति उत्पन्न करता है जिसे किसी अन्य मॉड्यूल में संकलित किया जा सकता है।मेटा-समारोह

{-# LANGUAGE TemplateHaskell #-} 
module GenFlipTH where 

import Language.Haskell.TH 

pull :: Int -> Q Exp 
pull 0    = varE 'flip 
pull n | n < 0  = fail "Negative arity" 
     | otherwise = [| fmap $(pull (n - 1)) . flip |] 
-- Here we use the fact that `(->) r` is a functor. 

के रूप में परिभाषित किया जा सकता है और एक अन्य मॉड्यूल में इस्तेमाल किया

{-# LANGUAGE TemplateHaskell #-} 
import GenFlipTH 

flip3 :: (a -> b3 -> b2 -> b1 -> b -> c) -> (b3 -> b2 -> b1 -> b -> a -> c) 
flip3 = $(pull 3) 

यह शायद अपनी आवश्यकताओं के बंद कर देता है है मैं प्राप्त कर सकते हैं की तरह उचित अभिव्यक्ति उत्पन्न करने के लिए - यदि आप एक से समारोह का निर्धारण संख्या और संकलन-समय गारंटी प्राप्त करें कि यह सही ढंग से बनाया और उपयोग किया गया है।

+0

वैसे, क्या हम एक वर्ग को परिभाषित कर सकते हैं जो मौजूदा वर्ग का पूरक है। यदि यह संभव है तो मैं बता सकता हूं कि एक चर एक फ़ंक्शन है या नहीं, या फ़ंक्शन की पैरामीटर की संख्या भी है। – TorosFanny

+0

@TorosFanny एक वर्ग के पूरक द्वारा आपका क्या मतलब है? मेरा मानना ​​है कि आप पैरामीटर की संख्या स्वचालित रूप से नहीं बता सकते हैं। पसंद है, क्या एक -> बी -> सी -> डी' में एक, दो या तीन पैरामीटर हैं? –

+0

वर्तमान में, मैं केवल उन कार्यों के लिए पैरामीटर की संख्या बता सकता हूं जो "अंतिम परिणाम" प्रकारों के प्रकार हैं जिन्हें मैंने विशेष रूप से शून्य के रूप में परिभाषित किया है। देखें: http: //stackoverflow.com/questions/17318107/is-there-a- सामान्य-way-to-tell-the-number-of-parameters-of-a-function-in-haskell – TorosFanny

3

आप इसे सामान्य कार्य के रूप में नहीं कर सकते हैं, क्योंकि फ़ंक्शन का प्रकार इनपुट के आधार पर अलग-अलग होगा। आप इसे टाइपक्लास और कार्यात्मक निर्भरताओं द्वारा पेश किए गए विज्ञापन-प्रसार बहुरूपता के साथ कर सकते हैं। हालांकि, फिर भी आपको ओलेग के IsFunction जैसे कुछ अनुमति देने के लिए कई एक्सटेंशन की आवश्यकता होगी (देखें: http://okmij.org/ftp/Haskell/isFunction.lhs)। यह गुम टुकड़ा है जो आपको पहचानने देता है कि क्या आप टाइपक्लास रिकर्सन के मूल मामले तक पहुंच गए हैं।

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

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