मैं फिक्स का उपयोग कैसे करूं, और यह कैसे काम करता है?


87

मैं प्रलेखन के लिए थोड़ा उलझन में था fix(हालांकि मुझे लगता है कि मैं समझता हूं कि यह अब क्या करना चाहिए), इसलिए मैंने स्रोत कोड को देखा। इसने मुझे और भ्रमित कर दिया:

fix :: (a -> a) -> a
fix f = let x = f x in x

यह वास्तव में एक निश्चित बिंदु कैसे लौटाता है?

मैंने कमांड लाइन पर इसे आज़माने का फैसला किया:

Prelude Data.Function> fix id
...

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


68
शरारत का जवाब है, "फिक्स का कोई वास्तविक उपयोग नहीं है, यह सिर्फ इतना है कि आप fix errorghci में टाइप कर सकते हैं और अपने बारे में अच्छा महसूस कर सकते हैं ।"
थॉमस एम। डुबिसन

3
@TomMD - मजेदार। मुझे याद होगा कि अगर कोई मुझसे कभी पूछता है कि क्या ठीक है और मैं अलंकार महसूस कर रहा हूं। :-)
जेसन बेकर

2
मैं आमतौर पर लिखने fixके रूप में fix f = f (fix f)। लघु, सरल, कार्य और गणितीय परिभाषा के समान।
newacct

20
@ नया, हाँ, यह है कि मैं यह भी कैसे लगता है। लेकिन यहाँ एक और अधिक कुशल संरचनाओं को जन्म दे सकता है। यदि आप मूल्यांकन करते हैं, कहते हैं, तो आप अंतर देख सकते हैं fix (1:) !! (10^8)। मूल इसे निरंतर मेमोरी में करता है, आपका रैखिक मेमोरी लेता है (जो इसे थोड़ा धीमा बनाता है, भी)। यही है, चलो "एक तंग गाँठ बांधता है" का उपयोग करते हुए, और एक परिपत्र डेटा संरचना उत्पन्न करने की अनुमति देता है, जबकि आपका नहीं है।
लुकी

22
आप फिर से आविष्कार fixभी कर सकते थे! मुझे fixबहुत समझने में मदद की ।
fredoverflow

जवाबों:


90

आप कुछ भी गलत नहीं कर रहे हैं। fix idएक अनंत लूप है।

जब हम कहते हैं कि fixकिसी फ़ंक्शन का न्यूनतम निश्चित बिंदु लौटाता है, तो हमारा मतलब है कि डोमेन सिद्धांत अर्थ में। तो fix (\x -> 2*x-1)है नहीं लौटने के लिए जा रहा 1, क्योंकि यद्यपि 1कि समारोह की एक निश्चित बिंदु है, ऐसा नहीं है कम से कम डोमेन आदेश में एक।

मैं एक या दो पैराग्राफ में डोमेन ऑर्डरिंग का वर्णन नहीं कर सकता, इसलिए मैं आपको ऊपर दिए गए डोमेन सिद्धांत लिंक का उल्लेख करूंगा। यह एक उत्कृष्ट ट्यूटोरियल, पढ़ने में आसान और काफी ज्ञानवर्धक है। मैं इसकी पुरजोर सलाह देता हूँ।

10,000 फीट से देखने के लिए, fixएक उच्च-क्रम फ़ंक्शन है जो पुनरावृत्ति के विचार को एन्कोड करता है । यदि आपके पास अभिव्यक्ति है:

let x = 1:x in x

अनंत सूची में कौन से परिणाम हैं [1,1..], आप एक ही बात कह सकते हैं fix:

fix (\x -> 1:x)

(या बस fix (1:)), जो कहता है कि मुझे (1:)फ़ंक्शन का एक निश्चित बिंदु मिल गया है, IOW एक ऐसा मान xहै x = 1:x... जैसे हमने ऊपर परिभाषित किया है। जैसा कि आप परिभाषा से देख सकते हैं, fixइस विचार से अधिक कुछ नहीं है - पुनरावृत्ति एक फ़ंक्शन में संलग्न है।

यह वास्तव में पुनरावृत्ति की सामान्य अवधारणा है - आप इस तरह से किसी भी पुनरावर्ती कार्य को लिख सकते हैं, जिसमें पॉलीमॉर्फिक पुनरावृत्ति का उपयोग करने वाले फ़ंक्शन भी शामिल हैं । इसलिए उदाहरण के लिए विशिष्ट फंक्शनल फंक्शन:

fib n = if n < 2 then n else fib (n-1) + fib (n-2)

fixइस तरह से लिखा जा सकता है :

fib = fix (\f -> \n -> if n < 2 then n else f (n-1) + f (n-2))

व्यायाम: fixयह दिखाने के लिए कि ये दो परिभाषाएँ fibसमतुल्य हैं , की परिभाषा का विस्तार करें ।

लेकिन पूरी समझ के लिए, डोमेन सिद्धांत के बारे में पढ़ें। यह वास्तव में अच्छा सामान है।


32
यहां सोचने का संबंधित तरीका है fix id: fixप्रकार का एक फ़ंक्शन लेता है a -> aऔर प्रकार का मान लौटाता है a। क्योंकि idकिसी के लिए बहुरूपी है a, fix idप्रकार होगा a, किसी भी संभावित मूल्य अर्थात्। हास्केल में, एकमात्र मूल्य जो किसी भी प्रकार का हो सकता है नीचे है, and, और एक गैर-समाप्ति कम्प्यूटेशन से अप्रभेद्य है। तो fix idवास्तव में इसका क्या मूल्य है, नीचे मूल्य पैदा करता है। इसका एक खतरा fixयह है कि यदि then आपके फ़ंक्शन का एक निश्चित बिंदु है, तो यह न्यूनतम निर्धारित बिंदु है, इसलिए fixइसे समाप्त नहीं किया जाएगा।
जॉन एल

4
@ हॉसल में जॉनल undefinedभी किसी भी प्रकार का एक मूल्य है। आप के fixरूप में परिभाषित कर सकते हैं fix f = foldr (\_ -> f) undefined (repeat undefined):।
didest

1
@ कोड आपके कोड के बराबर है _Y f = f (_Y f)
विल नेस

25

मैं यह सब समझने का दावा नहीं करता, लेकिन अगर यह किसी की मदद करता है ... तो yippee।

की परिभाषा पर विचार करें fixfix f = let x = f x in x। दिमाग़ी हिस्सा वह xहै जिसे परिभाषित किया जाता है f x। लेकिन एक मिनट के लिए इसके बारे में सोचो।

x = f x

चूंकि x = fx, तो हम xउस के दाहिने हाथ की तरफ के मूल्य को प्रतिस्थापित कर सकते हैं , है ना? तो इसलिए...

x = f . f $ x -- or x = f (f x)
x = f . f . f $ x -- or x = f (f (f x))
x = f . f . f . f . f . f . f . f . f . f . f $ x -- etc.

तो चाल है, समाप्त करने के लिए, fकिसी प्रकार की संरचना उत्पन्न करना है, ताकि बाद में fपैटर्न उस संरचना से मेल खा सके और पुनरावर्तन को समाप्त कर सके, वास्तव में अपने पैरामीटर (?) के पूर्ण "मूल्य" की परवाह किए बिना?

जब तक, निश्चित रूप से, आप एक अनंत सूची बनाने जैसा कुछ करना चाहते हैं, जैसा कि ल्यूकी सचित्र है।

टॉमएमडी की तथ्यात्मक व्याख्या अच्छी है। फिक्स का प्रकार हस्ताक्षर है (a -> a) -> a। दूसरे शब्दों में, के लिए प्रकार हस्ताक्षर (\recurse d -> if d > 0 then d * (recurse (d-1)) else 1)है । तो हम ऐसा कह सकते हैं । इस तरह, फिक्स हमारे फ़ंक्शन को लेता है, जो कि , या वास्तव में है , और दूसरे शब्दों में , दूसरे शब्दों में, दूसरे फ़ंक्शन में टाइप का परिणाम देगा !(b -> b) -> b -> b(b -> b) -> (b -> b)a = (b -> b)a -> a(b -> b) -> (b -> b)ab -> b

रुको, मैंने सोचा कि यह एक निश्चित बिंदु पर लौटना चाहिए था ... एक फ़ंक्शन नहीं। ठीक है, यह कार्य करता है (चूंकि फ़ंक्शन डेटा हैं)। आप कल्पना कर सकते हैं कि इसने हमें एक तथ्य खोजने के लिए निश्चित कार्य दिया। हमने इसे एक फ़ंक्शन दिया है जो यह नहीं जानता है कि कैसे पुनरावृत्ति करना है (इसलिए इसका एक पैरामीटर पुनरावृत्ति के लिए उपयोग किया जाने वाला एक फ़ंक्शन है), और fixइसे पुनरावृत्ति करने का तरीका सिखाया।

याद रखें कि मैंने कैसे कहा कि fकिसी प्रकार की संरचना तैयार करनी है ताकि बाद में fपैटर्न मैच और समाप्त हो सके? खैर, यह बिल्कुल सही नहीं है, मुझे लगता है। टॉमएमडी ने उदाहरण दिया कि कैसे हम xफ़ंक्शन को लागू करने और आधार मामले की ओर कदम बढ़ा सकते हैं। अपने कार्य के लिए, यदि वह एक / / का उपयोग करता है, और यही समाप्ति का कारण बनता है। बार-बार प्रतिस्थापन के बाद, अंततः inकी पूरी परिभाषा के हिस्से को इसके fixसंदर्भ में परिभाषित किया जाना बंद हो जाता है xऔर यह तब होता है जब यह गणना योग्य और पूर्ण होता है।


धन्यवाद। यह बहुत उपयोगी और व्यावहारिक व्याख्या है।
kizzx2

17

आपको तय करने के लिए एक तरीका चाहिए। अपने उदाहरण का विस्तार यह स्पष्ट है कि यह खत्म नहीं होगा:

fix id
--> let x = id x in x
--> id x
--> id (id x)
--> id (id (id x))
--> ...

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

(fix (\f h -> if (pred h) then f (mutate h) else h)) q

डब्ल्यूटीएफ, आप कहते हैं! ठीक है, हां, लेकिन यहां कुछ उपयोगी बिंदु हैं। सबसे पहले, आपका पहला fixतर्क आमतौर पर एक फ़ंक्शन होना चाहिए जो 'रिकर्स' केस है और दूसरा तर्क वह डेटा है जिस पर कार्य करना है। यहाँ नामांकित फ़ंक्शन के समान कोड है:

getQ h
      | pred h = getQ (mutate h)
      | otherwise = h

यदि आप अभी भी भ्रमित हैं तो शायद फैक्टोरियल एक आसान उदाहरण होगा:

fix (\recurse d -> if d > 0 then d * (recurse (d-1)) else 1) 5 -->* 120

मूल्यांकन पर ध्यान दें:

fix (\recurse d -> if d > 0 then d * (recurse (d-1)) else 1) 3 -->
let x = (\recurse d -> if d > 0 then d * (recurse (d-1)) else 1) x in x 3 -->
let x = ... in (\recurse d -> if d > 0 then d * (recurse (d-1)) else 1) x 3 -->
let x = ... in (\d -> if d > 0 then d * (x (d-1)) else 1) 3

ओह, क्या आपने अभी देखा है? वह xहमारी thenशाखा के अंदर एक समारोह बन गया ।

let x = ... in if 3 > 0 then 3 * (x (3 - 1)) else 1) -->
let x = ... in 3 * x 2 -->
let x = ... in 3 * (\recurse d -> if d > 0 then d * (recurse (d-1)) else 1) x 2 -->

उपरोक्त में आपको याद रखने की आवश्यकता है x = f x, इसलिए x 2केवल के बजाय अंत में दो तर्क 2

let x = ... in 3 * (\d -> if d > 0 then d * (x (d-1)) else 1) 2 -->

और मैं यहाँ रुक जाऊँगा!


आपका जवाब वही है जो वास्तव में fixमेरे लिए मायने रखता है। मेरा जवाब काफी हद तक उस पर निर्भर करता है जो आपने पहले ही कहा है।
डैन बर्टन

@ थोमस आपके दोनों कमी क्रम गलत हैं। :) id xबस कम कर देता है x(जो फिर वापस कम कर देता है id x)। - फिर, 2 सैंपल ( fact) में, जब xपहली बार थंक को मजबूर किया जाता है, जिसके परिणामस्वरूप मूल्य को याद किया जाता है और पुन: उपयोग किया जाता है। गैर-साझाकरण परिभाषा के (\recurse ...) xसाथ पुनर्गणना होगी , इस साझाकरण परिभाषा के साथ नहीं । - मैंने यहाँ परीक्षण संपादित किया है - यदि आप इसे स्वीकार करते हैं, तो आप इसका उपयोग करने के लिए स्वागत कर सकते हैं। y g = g (y g)fix
विल नेस

वास्तव में, जब fix idकम किया जाता है, तो फ्रेम (थंक) के अंदर let x = id x in xअनुप्रयोग के मूल्य को भी मजबूर करता है , इसलिए यह कम हो जाता है , और यह छोरों। ऐसा दिखता है। id xletlet x = x in x
नेस

सही बात। मेरा जवाब समसामयिक तर्क का उपयोग कर रहा है। कमी को एक ला हास्केल दिखा रहा है, जो मूल्यांकन आदेश के साथ खुद को चिंतित करता है, केवल उदाहरण के लिए बिना किसी सच्चे लाभ के भ्रमित करने का कार्य करता है।
थॉमस एम। डुबिसन

1
प्रश्न को हैसेल और लेटरेक (यानी पुनरावर्ती लेट, शेयरिंग के साथ) दोनों के साथ टैग किया गया है। हास्केल में Yfix और Y के बीच का अंतर बहुत स्पष्ट और महत्वपूर्ण है। मैं यह नहीं देखता कि सही कमी आदेश को गलत तरीके से दिखाने से क्या अच्छा होता है जब सही, कम स्पष्ट, बहुत स्पष्ट और अनुसरण करने में आसान होता है, और सही ढंग से प्रतिबिंबित होता है कि वास्तव में क्या चल रहा है।
विल नेस

3

मैं इसे कैसे समझता हूं, यह फ़ंक्शन के लिए एक मान पाता है, जैसे कि यह उसी चीज़ का आउटपुट देता है जो आप इसे देते हैं। पकड़ है, यह हमेशा अपरिभाषित (या अनन्त लूप का चयन करेगा, हैस्केल में, अपरिभाषित और अनंत लूप समान हैं) या जो भी इसमें सबसे अधिक अपरिभाषित है। उदाहरण के लिए, आईडी के साथ,

λ <*Main Data.Function>: id undefined
*** Exception: Prelude.undefined

जैसा कि आप देख सकते हैं, अपरिभाषित एक निश्चित बिंदु है, इसलिए fixइसे चुना जाएगा। यदि आप इसके बजाय (\ x-> 1: x) करते हैं।

λ <*Main Data.Function>: undefined
*** Exception: Prelude.undefined
λ <*Main Data.Function>: (\x->1:x) undefined
[1*** Exception: Prelude.undefined

तो fixअपरिभाषित नहीं ले सकते। इसे अनंत छोरों से थोड़ा और जुड़ा बनाने के लिए।

λ <*Main Data.Function>: let y=y in y
^CInterrupted.
λ <*Main Data.Function>: (\x->1:x) (let y=y in y)
[1^CInterrupted.

फिर से, एक मामूली अंतर। तो निश्चित बिंदु क्या है? हमें कोशिश करते हैं repeat 1

λ <*Main Data.Function>: repeat 1
[1,1,1,1,1,1, and so on
λ <*Main Data.Function>: (\x->1:x) $ repeat 1
[1,1,1,1,1,1, and so on

यह समान हे! चूंकि यह एकमात्र निश्चित बिंदु है, इस fixपर समझौता करना चाहिए। क्षमा करें fix, आपके लिए कोई अनंत लूप या अपरिभाषित नहीं है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.