Expressing Y in term of SKI-Combinators in JavaScript - javascript

I was fiddling with combinators in JavaScript and was being proud of (hopefully) getting S to work when I stumbled upon Wikipedia saying: "The Y combinator can be expressed in the SKI-calculus as: Y = S (K (S I I)) (S (S (K S) K) (K (S I I)))", so I had to try that:
var I = function (x) {
return x;
};
var K = function (x) {
return function(){
return x;}
};
var S = function (x) {
return function (y) {
return function (z) {
return x(z)(y(z));
}
}
};
var Y = S (K(S(I)(I))) (S(S(K(S))(K)) (K(S(I)(I))));
Y; //evals to:
//function (z) {return x(z)(y(z));}
//And this (lifted from Crockford's Site):
var factorial = Y(function (fac) {
return function (n) {
return n <= 2 ? n : n * fac(n - 1);
};
}); //fails:
//RangeError: Maximum call stack size exceeded
What am I doing wrong? Am I not translating that expression correctly? Is there something wrong with how I'm going about this? Does it even make sense? Most of what's to be read about stuff like this just makes my brain want to explode, so the point of this exercise for me was mainly to see if I understood the notation (and would thus be able to translate it to JavaScript).
Oh, and, by the way: what got me reading & fiddling again was that what prototype.js implements as Prototype.K is actually the I combinator. Has anyone noticed?

The problem here is that you are using a strictly evaluated programming language. The Y-combinator, pretty much like any other fixed point combinator, will only work properly when your functions are called by need, or 'lazily evaluated'.
I know of a way to work around this (one of my professors looked into it a while ago), but it will make your code completely unreadable.
Below I've shown what's going on exactly, hoping you can see why JavaScript can't handle a straightforward implementation of SKI-calculus.
This is what Y looks like after JavaScript evaluated your SKI-expression:
var Y = function (q) {
return (function(p){return q(p(p))})(function(p){return q(p(p))});
};
Now let's see what happens if you feed it your function function (fac) { ... }. Let's call that function f:
var factorial = (function(p){return f(p(p))})(function(p){return f(p(p))});
Since the first anonymous function is applied to an argument, it will be evaluated into this:
var factorial = f(
(function(p){return f(p(p))})(function(p){return f(p(p))})
);
In a lazily evaluated language, the argument to f would now be left alone, and f itself would be evaluated. However, because JavaScript is a strictly evaluated language (or 'call-by-value'), it wants to know what argument it needs to pass to function f before actually running that function. So let's evaluate that argument, shall we?
var factorial = f(f(
(function(p){return f(p(p))})(function(p){return f(p(p))})
)
);
I guess now you're starting to see now where things go wrong, and how the Y-combinator actually works. In any case, your JavaScript machine will run out of stack space, because it's trying to build an infinite stack of calls to f.

Related

Is CallCC an improved version of goto?

My background is Javascript, Python & a bit of Haskell. I am trying to understand callCC, there are many explanations but I can't find them trivial & I came across this https://www.cs.bham.ac.uk/~hxt/research/Logiccolumn8.pdf and I felt like I almost got it but I need some help to understand C code.
Below is the Code for Jumping back into a function in GNU C.
void *label_as_result() {
return &&L;
L: printf("Jumped back into the function. \n");
}
main () {
void *p;
p = label_as_result();
printf("The function returned; now jump back into it.\n");
goto *p;
}
What does return statement do in label_as_result function?
Does p in main store the stack frame in heap & the instruction line where it is stopped?
Jump back to function means create a stack frame again and continue from where we left?
Below this code there is paragraph
But in a language with first-class functions and callCC, no such implementation restrictions apply. Just as with the label as a result in C, we can return a continuation introduced by callCC from a function so as to jump back into the function. When we did this with goto, the stack was smashed, but with callCC the function just returns again. Consider the following function
λ(). callCC(λk. λx. throw k (λy. x))
The continuation k is returned as part of the result, roughly analogous to returning a label as the result in C.
What does stack was smashed, he meant stackoverflow can happen if you use goto? How callCC is getting around this problem using trampolining?
As many say callCC gives Early return semantics that means is it like yield in python or Javascript?
Is it possible to write callCC in Javascript using yield?
How I conceive the above code in Javascript
function* label_as_result() {
yield () => console.log("Jumped back into the function.");
}
p = label_as_result().next().value;
console.log("The function returned; now jump back into it.");
p();
It can even simple be written without any generators concept as
function label_as_result() {
return () => console.log("Jumped back into the function.");
}
p = label_as_result();
console.log("The function returned; now jump back into it.");
p();
That means callCC is a function that returns a continuation but all other functions take continuations.
Continuations are like Undecided code that need to be performed in future but callCC is like predefined code that needs to be performed in Future? (I am talking in perspective of a framework and the user's code)
What does return statement do in label_as_result function?
It returns the address of the instruction labelled L. That is, it returns the address of where the code the compiler generated for printf("Jumped back into the function. \n"); is stored in memory.
Does p in main store the stack frame in heap & the instruction line where it is stopped?
No, it stores the instruction line where the L label is. That's all it stores.
Jump back to function means create a stack frame again and continue from where we left?
No, it means a single jump and nothing else - no stack manipulation. The control flow jumps to the line labelled L, but nothing else changes. The stack remains unchanged.
What does stack was smashed, he meant stackoverflow can happen if you use goto?
Underflow, actually. When label_as_result is called, a frame is pushed to the stack. When it returns, that frame is popped. Then we jump to L, execute printf and then reach the end of the function, which will pop the stack again. So in the end the stack was popped more often than it was pushed.
How callCC is getting around this problem
By actually doing what you assumed the C code was doing: Saving and restoring the stack instead of just jumping to a code line while keeping the stack the same.
As many say callCC gives Early return semantics that means is it like yield in python or Javascript?
They're alike in the sense that they both give you a type of early return and they can be used for some of the same things. You can think of yield as a more specialized tool meant to provide a simpler way to achieve some of the use cases of callCC.
Is it possible to write callCC in Javascript using yield?
No, but it's possible to write yield in Scheme using callCC. callCC is strictly the more powerful of the two.
How I conceive the above code in Javascript
The actual C code isn't something that you can replicate in JavaScript (other than by building a mini-VM with its own stack) because JavaScript doesn't allow you to destroy the stack like that.
A non-broken version that doesn't destroy the stack could be accomplished by returning a function from label_as_result as you do in your second code sample.
That means callCC is a function that returns a continuation
callCC is a function that calls another function with the current continuation. That can be used to return the continuation.
Continuations are like Undecided code that need to be performed in future
Sure, except I wouldn't say "need" here. You don't have to invoke the continuation (or you could invoke it more than once even).
but callCC is like predefined code that needs to be performed in Future?
Not quite sure what you mean here, but that doesn't sound right. callCC is a function that gives you access to the current continuation.
try, throw, catch
callcc can be implemented in direct style using try-catch. The important bit is that the continuation must "box" the return value and "unbox" it in catch to avoid swallowing real errors. Here is a straightforward implementation in JavaScript -
const callcc = f => {
class Box { constructor(v) { this.unbox = v } }
try { return f(value => { throw new Box(value) }) }
catch (e) { if (e instanceof Box) return e.unbox; throw e }
}
console.log(5 + callcc(exit => 10 * 3))
console.log(5 + callcc(exit => 10 * exit(3)))
console.log(5 + callcc(exit => { exit(10); return 3 }))
console.log(5 + callcc(exit => { exit(10); throw Error("test failed") }))
try {
console.log(5 + callcc(exit => { throw Error("test passed!") }))
}
catch (e) {
console.error(e)
}
.as-console-wrapper { min-height: 100%; top: 0; }
35 ✅ 5 + 10 * 3
8 ✅ 5 + 3
15 ✅ 5 + 10
15 ✅ 5 + 10
Error: test passed! ✅ Errors are not swallowed
early return
Given a list of numbers, let's multiply all of them. As humans we know if a single 0 is present, the product must be 0. callcc allows us to encode that same short-circuiting behavior. In the demo below mult(a,b) is used so we can see when actual work is happening. In a real program it could be replaced with a * b -
const callcc = f => {
class Box { constructor(v) { this.unbox = v } }
try { return f(value => { throw new Box(value) }) }
catch (e) { if (e instanceof Box) return e.unbox; throw e }
}
const apply = (x, f) => f(x)
const mult = (a, b) => {
console.log("multiplying", a, b)
return a * b
}
console.log("== without callcc ==")
console.log(
apply([1,2,3,0,4], function recur(a) {
if (a.length == 0) return 1
return mult(a[0], recur(a.slice(1)))
})
)
console.log("== with callcc ==")
console.log(
callcc(exit =>
apply([1,2,3,0,4], function recur(a) {
if (a.length == 0) return 1
if (a[0] == 0) exit(0) // 🔍
return mult(a[0], recur(a.slice(1)))
})
)
)
.as-console-wrapper { min-height: 100%; top: 0; }
== without callcc ==
multiplying 4 1
multiplying 0 4 🔍 here we know the answer must be zero but recursion continues
multiplying 3 0
multiplying 2 0
multiplying 1 0
0
== with callcc ==
0 🔍 the answer is calculated without performing any unnecessary work
cursory benchmark
In a one-off metric, callcc performs at least 50-500 times faster on a list of 20,000 numbers ranging from 0-100 -
const callcc = f => {
class Box { constructor(v) { this.unbox = v } }
try { return f(value => { throw new Box(value) }) }
catch (e) { if (e instanceof Box) return e.unbox; throw e }
}
const apply = (x, f) => f(x)
const A = Array.from(Array(20000), _ => 0 | Math.random() * 100)
console.time("== without callcc ==")
console.log(
apply(A, function recur(a) {
if (a.length == 0) return 1n
return BigInt(a[0]) * recur(a.slice(1))
}).toString()
)
console.timeEnd("== without callcc ==")
console.time("== with callcc ==")
console.log(
callcc(exit =>
apply(A, function recur(a) {
if (a.length == 0) return 1n
if (a[0] == 0) exit(0) // 🔍
return BigInt(a[0]) * recur(a.slice(1))
})
).toString()
)
console.timeEnd("== with callcc ==")
.as-console-wrapper { min-height: 100%; top: 0; }
0
== without callcc ==: 466.000ms
0
== with callcc ==: 1.000ms
read on
callcc was originally implemented in this Q&A. Read on for additional info and examples.

How does the JS engine deal with explicitly typed computations?

I've been interested in meta-programming of late. We can take a generic computation, in this case the mean, and create an efficient, spelled out function on the fly for it. Here I'm creating, in mean2, a function that will compute the mean explicitly (without loops). Generally, these explicit functions run more quickly. But I'm experiencing some interesting behavior. In my timings, for an array of size 50 ran in 4e7 loops, the explicit function wins handily as anticipated:
symbolic: 2479.273ms | literal: 60.572ms
But nudge the initial array size from 50 to say 55, the performance dives precipitously.
symbolic: 2445.357ms | literal: 3221.829ms
What could be the cause of this?
const A = new Float64Array(50).map(Math.random)
const mean1 = function (A) {
let sum = 0
for (let i = 0; i < A.length; i++)
sum += A[i]
return sum / A.length
}
const mean2 = (function (A) {
return new Function('A', `
return (${new Array(A.length).fill(null).map(function (_, i) {
return `A[${i}]`
}).join('+')}) / ${A.length}
`)
})(A)
console.time('symbolic')
for (let i = 0; i < 4e7; i++)
mean1(A)
console.timeEnd('symbolic')
console.time('literal')
for (let i = 0; i < 4e7; i++)
mean2(A)
console.timeEnd('literal')
The result is being cached in the 2nd example, it has little to do with the "meta-programming" method, (or more specifically the lack of a loop).
This is not so easy to directly prove with JavaScript; in a compiled language you would usually just look at the assembly and see that the compiler has tried to be clever in some way and optimise out your loop inside the timer. JS runtimes are obviously more opaque and complex, the output is not so easily accessible. You can instead test for it by proxy, by observing the behaviour of different but equivalent forms to see what triggers the up-front optimisations.
The following slight modifications of your "mean2" function escape caching optimisations in nodejs (v8) at time of testing:
Assign to a scoped variable before return:
const mean2 = (function (A) {
return new Function('A', `
let sum = (${new Array(A.length).fill(null).map(function (_, i) {
return `A[${i}]`
}).join('+')}) / ${A.length};
return sum;
`)
})(A)
Use A.length reference instead of literal:
const mean2 = (function (A) {
return new Function('A', `
return (${new Array(A.length).fill(null).map(function (_, i) {
return `A[${i}]`
}).join('+')}) / A.length
`)
})(A)
You needn't worry about these subtitles though... instead change your testing methodology, ensure samples cannot be thrown away to produce the same result, otherwise you risk testing the compiler's ability to omit useless instructions instead of real performance.
In this case, re-initialise the array with random values before each sample, and to be absolutely sure - make some persistent variable dependent on the result of each sample. Also do not include these extra steps in the timer otherwise it will bias your sample time.

Creating an Arithmetic Task Runner

I have been tasked to create an Arithmetic Task Runner as part of my assignment.
Up until today I've never used NodeJS or even the terminal to execute a script.
I have been working on this for the past 5 hours and still no luck. I have avoided coming here and asking as I'd like to figure it out for myself, however, I have succumbed to desperately needing help.
This is the code I have so far:
class ArithmeticTaskRunner {
static set taskCount(counter) {
throw new('This is a readOnly accessor, the value is ${value}');
}
add(y) {
this.y = y || 0
console.log(y)
}
minus(x) {
this.x = Math.abs(this.y) * -1;
console.log(this.x);
};
multiply(z) {
this.z = z * this.x;
console.log(this.z)
}
execute(startValue) {
this.startValue = startValue + this.y
this.y = this.startValue
console.log(this.startValue)
this.startValue = this.minus
console.log(this.startValue)
this.startValue = this.multiply(this.startValue)
console.log(this.startValue)
}
}
tasks = [
function() { minus()},
function() { multiply(z)},
function() { add(x)},
function() { execute(x)}
]
This is nowhere near perfect, but it's 80%-90% near completion.
This is the task I have been given:
You should implement a class called ArithmeticTaskRunner with the following:
- An instance variable named tasks which is initialised to an empty array upon
creation.
- A method named addNegationTask which adds an anonymous function to the
tasks array. This anonymous function should take one argument, x, and return the
negation, -x.
- A method named addAdditionTask which takes a single argument y, and adds
an anonymous function to the tasks array. This anonymous function should take
one argument, x, and return the result x + y.
- A method named addMultiplicationTask which takes a single argument y,
and adds an anonymous function to the tasks array. This anonymous function
should take one argument, x, and return the result x * y.
- A read-only accessor named taskCount which returns the number of queued tasks.
- A method named execute, which takes a single argument named startValue.
If omitted, startValue defaults to zero. Starting at startValue, this method should iterate over the tasks array executing each function on the current value. It then returns the resulting number after all arithmetic operations have been executed.
I'd be grateful for any help I could get.
The issues I have are the following: The execute method (trying to make the startValue, after the addition, a negative), the multiplication method and the fact I cannot call the addition method twice without overriding the value. The examples of the program fully working have shown I should allow for a method to be called multiple times without overriding the previous value.
I know there's a rule where it's one question per issue, I concede that. But if anyone can help me out with any of the issues I will truly be grateful and I will compensate people for their efforts.
Thank you.
Edit - This is an example of both the expected inputs/outputs
> let taskRunner = new ArithmeticTaskRunner()
undefined
> taskRunner.addAdditionTask(2)
undefined
> taskRunner.addMultiplicationTask(4)
undefined
> taskRunner.addAdditionTask(10)
undefined
> taskRunner.execute(2)
26
> taskRunner.execute(-2)
10
I don't want to provide the whole answer because this is an assignment for you, but here's some code that might help you out. This starts with 5 then calls doubleIt and then calls addOne to arrive at 11.
It does this by creating an array of functions, each one performs a simple task and returns the result of its input modified in some way.
Then it creates a function called execute that uses Array.reduce to call the first function in the array with a given initial value, then repeatedly calls each function in the array on the result. Check the documentation for Array.reduce if you're confused about how it works.
doubleIt = x => x * 2;
addOne = x => x + 1;
tasks = [doubleIt, addOne];
execute = (initial) => tasks.reduce((x,fn) => fn(x), initial)
document.write(execute(5))
Hint #2
class ArithmeticTaskRunner {
constructor() {
this.tasks = [];
}
addAdditionTask(arg) {
this.tasks.push(x => x + arg);
}
addMultiplicationTask(arg) {
this.tasks.push(x => x * arg);
}
execute(startValue) {
return this.tasks.reduce((x, fn) => fn(x), startValue);
}
}
let taskRunner = new ArithmeticTaskRunner()
taskRunner.addAdditionTask(2)
taskRunner.addMultiplicationTask(4)
taskRunner.addAdditionTask(10)
document.write(taskRunner.execute(2));
document.write(', ');
document.write(taskRunner.execute(-2));

What is being passed into this 'function(x)'?

I'm having a hard time grasping some finer details of javascript, I have this function function(x) it doesn't seem to be receiving any parameters. Maybe I'm not understanding the Math.sin part. I'm not sure. Any ideas on what is happening?
function makeDerivative( f, deltaX )
{
var deriv = function(x) // x isn't designated anywhere
{
return ( f(x + deltaX) - f(x) )/ deltaX;
}
return deriv;
}
var cos = makeDerivative( Math.sin, 0.000001);
// cos(0) ~> 1
// cos(pi/2) ~> 0
Update
I tried this instead and got NaN, then 15
function addthings(x, y)
{
var addition = function(m)
{
return( x + y + m);
}
return addition;
}
var add = addthings(5, 5);
alert(add());
alert(add(5));
To understand how that code works you have to read more about currying in functional javascript and functions closures.
The outer function returns the inner function, so everything you pass to
cos later theoretically is what you pass into the inner function. Imagine calling it like this:
console.log(makeDerivative( Math.sin, 0.000001)(0)); // 1
would output the same as if you're doing it as described
console.log(cos(0)) // 1
as cos is assigned reference to a function (the one that gets returned by makeDerivative).
The other answers touch on the issue, but I'm going to try to get to the core of it.
JavaScript variables are untyped, which means that they can dynamically change what kind of variable they are. On a simple level, this means that var a can be instantiated as an array, and then later assigned as a string on the fly.
But you can also store entire functions within those untyped variables. For example;
var test = 'hey'
console.log(test) //:: hey
test = function(input){ console.log('inner function: ' + input) }
console.log(test) //:: function(input){ console.log('inner function' + input) }
test() //:: inner function
test('with input') //:: inner function with input
Where //:: _____ represents the output to the console.
So the function you are using returns another dynamic function. You can then call that function in a normal fashion, inputting the value for x when you call it.
Well, you don't really call the function in the code you posted.
The makeDerivative gets reference to Math.sin function and inside it uses it to create reference to function which compute derivation of the passed function (see the f parameter).
In your example this reference is assigned to cos variable. If you called it with (0) argument, you would get 1 as return value and the argument (0) would be passed into that deriv function...

Trouble understanding a basic concept in Javascript Higher Order Functions

I am having a little bit of trouble understanding Higher Order Functions in javascript.
Can someone explain to me the difference of what's going on in these two situations?
Scenario 1:
// A function that takes in a number (x) and adds one to it.
function doMath(x){
return function (x){
return x + 1;
}
}
var didMath = doMath(5);
console.log(didMath()); // returns error
var didMath = doMath();
console.log(didMath(5)); // returns 6
var didMath = doMath(100);
console.log(didMath(5)); // still returns 6
Scenario 2:
function doMath2(x,callback){
return callback(x);
}
function add(x){
return x + 1;
}
console.log(doMath2(5,add)); // returns 6, works perfectly fine
I was under the impression that closures have access to parameters from their containing functions. Why is it that in Scenario 1, the "x" param in doMath is not accessible by the contained function?
what is happening here is you are never storing the value of x, you always return a new function, see this example it should work as you expect and maybe helps you to undersant
function doMath(x){
var y = x;
return function(y){
return y + 1;
}
}
In scenario 1
The first one outputs an error because the returned function expects an argument and you don't give one. If you remove the argument it works:
// A function that takes in a number (x) and adds one to it.
function doMath(x){
return function (){ // <--- here
return x + 1;
}
}
var didMath = doMath(5);
console.log(didMath());
In your two other examples you do give an argument and that is the one taken into account. Not the value that you give as parameter to doMath()

Categories