2016-09-17 8 views
6

निम्नलिखित को देखते हुए? मुझे समझ नहीं आता क्यों मुझे R.sum और R.length पारित कर सकते हैं, जब वे कार्य हैं और इसलिए, मैं कार्यों R.sum से अधिक उठाया R.divide और R.length निम्न उदाहरण में विपरीत मैप नहीं कर सकते हैं:मैं उठाए गए R.divide पर फ़ंक्शन कैसे पास कर सकता हूं?</p> <pre><code>var average = R.lift(R.divide)(R.sum, R.length) </code></pre> <p>कैसे आ इस <code>average</code> के pointfree कार्यान्वयन के रूप में काम करता है:

var sum3 = R.curry(function(a, b, c) {return a + b + c;}); 
R.lift(sum3)(xs)(ys)(zs) 

ऊपर मामले में मूल्यों xs, ys और zs को एक गैर निर्धारक संदर्भ में सम्मिलित किया गया है, इस मामले में उठाए गए कार्य को दिए गए कम्प्यूटेशनल संदर्भ में मानों पर लागू किया जाता है।

आगे बढ़ते हुए, मैं समझता हूं कि एक उठाए गए फ़ंक्शन को लागू करना प्रत्येक तर्क के लिए R.ap का उपयोग करना है।

R.ap(R.ap(R.ap([tern], [1, 2, 3]), [2, 4, 6]), [3, 6, 8]) 
R.lift(tern)([1, 2, 3], [2, 4, 6], [3, 6, 8]) 

प्रलेखन यह कहता है कि जांच की जा रही:

"लिफ्टों" arity> 1 इतना है कि यह "पर नक्शा" हो सकता है एक सूची, समारोह या अन्य के एक समारोह दोनों लाइनों एक ही उत्पादन के लिए मूल्यांकन ऑब्जेक्ट जो काल्पनिक लैंड को लागू करता है, उसे लागू करें।

और यह मेरे लिए कम से कम एक उपयोगी वर्णन की तरह प्रतीत नहीं होता है। मैं lift के उपयोग के संबंध में अंतर्ज्ञान बनाने की कोशिश कर रहा हूं। मुझे उम्मीद है कि कोई इसे प्रदान कर सकता है।

उत्तर

13

पहली अच्छी बात यह है कि a -> bmap का समर्थन कर सकता है। हां, फ़ंक्शंस फ़ैक्टर हैं!

के map के प्रकार पर विचार करें:

map :: Functor f => (b -> c) -> f b -> f c 

के Array साथ Functor f => f की जगह हमें एक ठोस प्रकार देने के लिए करते हैं:

map :: (b -> c) -> Maybe b -> Maybe c 
:

map :: (b -> c) -> Array b -> Array c 

के इस समय Maybe साथ Functor f => f की जगह चलो

सहसंबंध स्पष्ट है। के एक द्विआधारी प्रकार का परीक्षण करने के Either a साथ Functor f => f की जगह, करते हैं:

map :: (b -> c) -> Either a b -> Either a c 

हम अक्सर ba -> b के रूप में a से एक समारोह के प्रकार का प्रतिनिधित्व करते हैं, लेकिन वह वास्तव में सिर्फ Function a b के लिए चीनी है। के Function के साथ ऊपर हस्ताक्षर में लंबे फार्म का उपयोग करें और Either की जगह दो:

map :: (b -> c) -> Function a b -> Function a c 

तो, एक समारोह की मानचित्रण हमें एक समारोह जो मूल फ़ंक्शन द्वारा दिया गया मान पर b -> c समारोह लागू होगी देता है।

map :: (b -> c) -> (a -> b) -> (a -> c) 

सूचना कुछ भी: हम a -> b चीनी का उपयोग कर हस्ताक्षर पुनर्लेखन सकता है? compose का प्रकार क्या है?

compose :: (b -> c) -> (a -> b) -> a -> c 

तो compose सिर्फ map समारोह प्रकार के विशेष है!

दूसरी अच्छी बात यह है कि a -> bap का समर्थन कर सकते है। कार्य भी आवेदक मज़ेदार हैं! इन्हें काल्पनिक भूमि spec में Apply एस के रूप में जाना जाता है।

चलो ap के प्रकार पर विचार करें:

ap :: Apply f => f (b -> c) -> f b -> f c 

की जगह ले चलो Apply f => fArray साथ:

ap :: Array (b -> c) -> Array b -> Array c 
अब

, Either a साथ:

ap :: Either a (b -> c) -> Either a b -> Either a c 
अब

, Function a साथ:

ap :: Function a (b -> c) -> Function a b -> Function a c 

Function a (b -> c) क्या है? यह थोड़ा उलझन में है क्योंकि हम दो शैलियों को मिश्रित कर रहे हैं, लेकिन यह एक ऐसा फ़ंक्शन है जो a प्रकार का मान लेता है और b से c पर एक फ़ंक्शन देता है। के a -> b शैली का उपयोग पुनर्लेखन करते हैं:

ap :: (a -> b -> c) -> (a -> b) -> (a -> c) 

किसी भी प्रकार की जो map का समर्थन करता है और ap "उठाया" जा सकता है। के lift2 पर एक नज़र लेते हैं:

lift2 :: Apply f => (b -> c -> d) -> f b -> f c -> f d 

कि Function a संतुष्ट याद रखें लागू की आवश्यकताओं, इसलिए हम जगह ले सकता है Apply f => fFunction a साथ:

lift2 :: (b -> c -> d) -> Function a b -> Function a c -> Function a d 

है कौन सा अधिक स्पष्ट रूप से लिखा:

lift2 :: (b -> c -> d) -> (a -> b) -> (a -> c) -> (a -> d) 

चलिए अपनी प्रारंभिक अभिव्यक्ति पर फिर से जाएं:

// average :: Number -> Number 
const average = lift2(divide, sum, length); 

average([6, 7, 8]) क्या करता है? a ([6, 7, 8]) a -> b फ़ंक्शन (sum) पर दिया गया है, b (21) का उत्पादन। a भी a -> c समारोह (length) को दिया जाता है, एक c (3) का निर्माण किया। अब हमारे पास b और c है, हम उन्हें b -> c -> d फ़ंक्शन (divide) पर d (7) बनाने के लिए फ़ीड कर सकते हैं, जो अंतिम परिणाम है।

तो, क्योंकि समारोह प्रकार map और ap समर्थन कर सकते हैं, हम converge किसी कीमत पर मिलता है (lift, lift2, और lift3 के माध्यम से)। मैं वास्तव में रामदा से converge को हटाना चाहता हूं क्योंकि यह आवश्यक नहीं है।


नोट कि मैं जानबूझकर इस जवाब में R.lift का उपयोग कर से बचा। किसी भी धर्मार्थ के कार्यों का समर्थन करने के फैसले के कारण इसका अर्थहीन प्रकार हस्ताक्षर और जटिल कार्यान्वयन है। दूसरी ओर अभयारण्य की धैर्य-विशिष्ट उठाने के कार्यों में स्पष्ट प्रकार के हस्ताक्षर और मामूली कार्यान्वयन होते हैं।

+3

बहुत अच्छा! मुझे यह जवाब ब्लॉग पोस्ट में उठाए जाने को देखना अच्छा लगेगा! –

+0

जब '(बी -> सी -> डी) -> (ए -> बी) -> (ए -> सी) -> (ए -> डी) 'को एक संयोजक के रूप में लागू किया गया है, यह' पक्षी = एफ = > जी => एच => एक्स => एफ (जी (एक्स)) (एच (एक्स)) '। यह 'psi = f => g => x => y => f (g (x)) (g (y)) के समान दिखता है। मुझे आश्चर्य है कि इस पक्षी का नाम कैसा है? – ftor

+0

अपने स्वयं के प्रश्न का उत्तर देने के लिए: यह 'स्टार्लिंग' है, जो फ़ंक्शंस 'कॉन्स्ट एपी = एफ => जी => एक्स => एफ (एक्स) (जी (एक्स))' पर आवेदक के 'एपी' की संरचना है। रचना 'const comp = f => g => x => f (g (x)) ':' const starling_ = comp (comp (ap)) (comp) '। – ftor

0

जैसा कि मुझे एक ही मुद्दे को समझने में कठिनाई है, मैंने रामदा के स्रोत कोड से एक झलक लेने का फैसला किया। भविष्य में इस बारे में एक ब्लॉग पोस्ट लिखेंगे। इस बीच- मैंने टिप्पणी की कि कैसे रामदा के lift कदम से कदम कदम उठाते हैं।

से: https://gist.github.com/philipyoungg/a0ab1efff1a9a4e486802a8fb0145d9e

// Let's make an example function that takes an object and return itself. 
// 1. Ramda's lift level 
lift(zipObj)(keys, values)({a: 1}) // returns {a: 1} 

// this is how lift works in the background 
module.exports = _curry2(function liftN(arity, fn) { 
    var lifted = curryN(arity, fn); 
    return curryN(arity, function() { 
    return _reduce(ap, map(lifted, arguments[0]), Array.prototype.slice.call(arguments, 1)); // found it. let's convert no 1 to no 2 
    }); 
}); 

// 2. Ramda's reduce level 
reduce(ap, map(zipObj, keys))([values]) 
// first argument is the function, second argument is initial value, and the last one is lists of arguments. If you don't understand how reduce works, there's a plenty of resources on the internet 

// 3. Ramda's ap level 
ap(map(zipObj, keys), values) 

// how ap works in the background 
module.exports = _curry2(function ap(applicative, fn) { 
    return (
    typeof applicative.ap === 'function' ? 
     applicative.ap(fn) : 
    typeof applicative === 'function' ? // 
     function(x) { return applicative(x)(fn(x)); } : // because the first argument is a function, ap return this. 
    // else 
     _reduce(function(acc, f) { return _concat(acc, map(f, fn)); }, [], applicative) 
); 
}); 

// 4. Voilà. Here's the final result. 
map(zipObj, keys)({a: 1})(values({a: 1})) 

// Hope it helps you and everyone else! 
संबंधित मुद्दे