2016-07-19 19 views
0

Gegeben ist die folgende rekursive map Funktion:Kann eine rekursive Funktion in Curry-Form tail rekursiv sein?

const U = f => f(f); 
 
    
 
const map = f => U(h => acc => ([head, ...tail]) => head === undefined 
 
? acc 
 
: h(h)([...acc, f(head)])(tail))([]); 
 
    
 
const xs = [1,2,3,4,5]; 
 
console.log(map(x => x * x)([1,2,3,4,5]));

Offensichtlich h(h) der rekursive Aufruf nicht die letzte Aktion der rekursiven Funktion ist. Aber wenn der Stapel abgewickelt wird, geschieht alles, was passiert, dass der fertige Akkumulator ohne weitere Änderungen oder Operationen zurückgegeben wird. Ist map entgegen meiner Erwartungen tail rekursiv?

+0

Ich denke, diese Implementierung eine verwirrte 'map' ist. Es mischt "map" und "reduce" in einem Vorgang. Ich teile [gist: u.js, y.js] (https://gist.github.com/anonymous/6ccdd17b0b16f75bc38af2930ca6655f) um zu zeigen, dass zwei separate Prozeduren die Lesbarkeit von 'map' unterstützen. Ich habe auch eine Implementierung mit "Y" durchgeführt, um zu zeigen, wie die beiden Implementierungen miteinander verglichen werden. Sie wissen das wahrscheinlich, aber der einzige Unterschied zu "Y" ist, dass Sie nur "h" anstelle von "h (h)" anwenden. Oh und ja, Schwanz ruft überall hin. Jetzt warten wir nur auf eine Engine, die Tail Call Eliminierung implementiert ... – naomik

+0

Dank @naomik, stimme ich absolut mit Ihnen überein. Dies war nur eine Herausforderung, wie 'map' implementiert werden kann, ohne es von' reduce' abzuleiten. Ich hatte nicht die Absicht, dies zu veröffentlichen, bis mich die Curry-Anwendung in Schwanzposition verblüffte. – ftor

+0

Kein Problem **^_^** – naomik

Antwort

2

der rekursive Aufruf h(h) ist nicht die letzte Aktion der rekursiven Funktion

h(h) kein rekursiver Aufruf ist. Die …(tail) ist der rekursive Aufruf, und ja, es ist in einer Tail-Position.

Dies könnte deutlicher, wenn man fällt, dass overcomplicated U combinator (oder am wenigsten an den Y combinator sofort verwendet):

const map = f => { 
    const mapF = acc => ([head, ...tail]) => head === undefined 
    ? acc 
    : mapF([...acc, f(head)])(tail); 
    return mapF([]); 
}; 
+0

Danke, aber 'U' verhindert, dass' f' wiederholt werden muss ('h' though) und dass ein Block benötigt wird. Übrigens, wie heißen solche Pfeile mit '{}'? – ftor

+0

Wie ich angedeutet habe, können Sie 'Y' verwenden, um das zu tun, was die Deklaration von' mapF' tut, wenn Sie interessiert sind. Aber es ist nicht wirklich wichtig, ich habe diese Syntax nur für ein wenig Klarheit verwendet, der ursprüngliche Code ist genauso tail-rekursiv. Pfeile ohne einen präzisen Körper sind immer noch nur Pfeilfunktionen. – Bergi

+0

Oh mein Gott, der rekursive Aufruf wird ausgeführt, wenn die prozedurale Anwendung der Curry-Funktion beendet ist. Ich bin so ein ich ... ich habe es nicht gesehen! – ftor