Construct function from domain and image arrays in Javascript - javascript

I've come across a pretty basic task for functional programming, I can't solve in javascript:
I'm trying wo write a (higher order) function that takes two arrays domain and image and returns a function. The returned function should return the n-th element of the image when given that n-th element of the domain:
Example:
let f = makeFunction([a,b,c],[d,e,f]);
f(a) //returns d
f(b) //returns e
f(c) //returns f
f(x) //any other value returns undefined
First I was trying to solve this problem like it's commonly done in functional programming. (Example in Racket)
(define makeFunction
(lambda (domain image)
(lambda (x)
(cond
[(= x (first domain)) (first image)
[else ((makeFunction (rest domain) (rest image) x)]
)
)
)
)
However something like this isn't possible in js, since the Function constructor doesn't create a closure (see here). Therefor my second attempt was to simply stringify the arrays and include them in the function definition (I also included input checking):
function makeFunction(domain, image){
if(new Set(domain).size==domain.length&&domain.length==image.length){
return new Function("x",`return ${JSON.stringify(image)}[${JSON.stringify(domain)}.indexOf(x)]`);
}else{
throw new Error("The lists don't allow the creation of a function, because they either don't have the same length or the domain isn't unique.");
}
}
This function works as long as primitive data types are the only ones the domain contains. But as soon as it includes objects, or even cyclic data, I've no idea how to make this function work...
//works as expected:
let f = makeFunction([1,2,3,4,"foo"],[4,3,2,1,"bar"]);
//always returns undefined:
let g = makeFunction([{foo:"bar"},{bar:"foo"}],[{bar:"foo"},{foo:"bar"}]);
//returns an error, since JSON.stringify doesn't work on cyclic data:
let cyclicData = {};
cyclicData.self = cyclicData;
let h = makeFunction([cyclicData],["foo"]);
Hopefully you can help me with this one :)

You noticed the pain you experience with new Function but you could've constructed a function using the function keyword like you did for makeFunction.
The following JavaScript function literal syntaxes below create lexicographic closures.[1] We'll be using the last syntax because it's closest to Racket
function makeFunction (param1, param2, ...) { statement1; statement2; ... }
const makeFunction = function (param1, param2, ...) { statement1; statement2; ... }
const makeFunction = (param1, param2, ...) => { statement1; statement2; ... }
const makeFunction = (param1, param2, ...) => expression
Your Racket program translates directly into JavaScript so long as we provide the first and rest functions. Note that isEmpty was added so that makeFunction ([], []) still works
const isEmpty = (xs = []) =>
xs.length === 0
const first = (xs = []) =>
xs [0]
const rest = (xs = []) =>
xs.slice (1)
const makeFunction = (domain = [], image = []) =>
x =>
isEmpty (domain)
? undefined
: x === first (domain)
? first (image)
: makeFunction (rest (domain), rest (image)) (x)
const f =
makeFunction ([ 'a', 'b', 'c' ], [ 'd', 'e', 'f' ])
console.log (f ('a')) // d
console.log (f ('b')) // e
console.log (f ('c')) // f
console.log (f ('x')) // undefined
Array destructuring assignment and default arguments allow us to see another way we could write our functions
const Empty =
Symbol ()
const isEmpty = ([ x = Empty, ...xs ]) =>
x === Empty
const first = ([ x = Empty, ...xs ]) =>
x
const rest = ([ x = Empty, ...xs ]) =>
xs
Or we can skip creating intermediate functions first and rest and use destructuring syntaxes directly in makeFunction
const Empty =
Symbol ()
const makeFunction = ([ key = Empty, ...keys ], [ value = Empty, ...values ]) =>
x =>
key === Empty
? undefined
: x === key
? value
: makeFunction (keys, values) (x)
const f =
makeFunction ([ 'a', 'b', 'c' ], [ 'd', 'e', 'f' ])
console.log (f ('a')) // d
console.log (f ('b')) // e
console.log (f ('c')) // f
console.log (f ('x')) // undefined
As #user3297291 points out, you should be looking at Map as it can look up a key in logarithmic time – compared to linear (slower) time used by makeFunction
[1] Functions using arrow (=>) syntax have also have a lexicographical this value

You can return a function that returns a function, this will create a closure for you.
Example:
makeFunction = (domain, image) => ((element) => (image[domain.findIndex(d => d === element)]))
f = makeFunction([1,2,3,4, 'foo'], [4,3,2,1, 'bar']);
f(1) // 4
f(2) // 3
...

Have you looked at using javascript's Map? Its get method is almost what you're trying to implement:
const makeFunction = (domain = [], image = []) => {
const m = new Map(pairs(domain, image));
return m.get.bind(m);
};
let a = { foo: "bar" };
let f = makeFunction([1,2,3,4,"foo"],[4,3,2,1,"bar"]);
let g = makeFunction([ a ]);
let h = makeFunction([ a ], [ 1 ]);
console.log(f(1));
console.log(g(a));
console.log(h(a));
// This still won't work though:
console.log(h({ foo: "bar" }));
function pairs([x, ...xs], [y, ...ys], ps = []) {
return x && y
? pairs(xs, ys, [...ps, [x, y]])
: ps;
};
Its keys however are still checked "by reference". If you want { foo: "bar" } == { foo: "bar" } you'll have to write some custom equality comparer...

Related

How to get parameter of an arrow function inside another function?

I want to create a functions that returns the parameter of another function. I know I can use argument or rest operator to access parameter inside a function itself, but how can I get them outside that function?
const returnValue = (fn) => {
//How can I get the parameter of fn? Assume I know its arity.
}
For example:
const foo = 'bar'
const hello = 'world'
const returnFirstArgument = (val1, val2) => val1
const returnArgumentByPosition = (fn, num) => {
//Take fn as input, return one of its parameter by number
}
const returnSecondArgument = returnArgumentByPosition(returnFirstArgument(foo, hello), 1) //Expect it returns 'world'
What you want isn't possible to do without modifying how returnFirstArgument behaves. Take for example the below piece of code:
const x = 1 + 2;
console.log(x); // 3
Before a value is assigned to x, the expression 1 + 2 needs to be evaluated to a value. In this case 1 + 2 gets evaluated to 3, so x gets assigned to 3, that way when we print it, it prints the literal number 3 out in the console. Since it is now just a number, we can't tell how 3 was derived (it could have come from 0 + 3, 1 * 3, etc...).
Now take a similar example below:
const max = Math.max(1, 2);
console.log(max); // 2
The same idea here applies from above. First Math.max(1, 2) is evaluated to the value of 2, which is then assigned to max. Again, we have no way of telling how 2 was derived.
Now consider a function:
const add = (x, y) => x + y;
const ans = add(1 + 2, Math.max(1, 2));
console.log(ans); // 5
When we call the function, the function's arguments are first evaluated to values. The parameters within the function are then assigned to copies of these values:
const ans = add(1 + 2, Math.max(1, 2));
// ^--------^------------- both evaluate first before function is invoked
so the above function call becomes:
const ans = add(3, 2);
As a result, inside the add function, x becomes 3 and y becomes 2. Just like with the above first two examples with variables, we have no way of knowing the 3 came from the expression 1+2 and that 2 came from the function call of Math.max(1, 2).
So, relating this back to your original question. Your function call is analogous to the add function call shown above:
const returnSecondArgument = returnArgumentByPosition(returnFirstArgument(foo, hello), 1)
just like in the other examples, the arguments passed to the function can't be expressions, so they need to be evaluated first to values. returnFirstArgument(foo, hello) is evaluated to a value before the returnArgumentByPosition function is invoked. It will evaluate to the string "bar". This results in fn becoming "bar" inside of your returnArgumentByPosition. As "bar" is just a string, we again have to way of telling where it came from, and so, won't have access to the function which created it. As a result, we can't access the second argument of the function, since this information is not retained anywhere.
One approach to do what you're after is to create a recall function. The recall function is able to "save" the arguments you passed into it, and then expose them later. Put simply, it wraps your original function but is able to save the arguments and the result of calling your original function:
const recall = fn => (...args) => {
return {
args,
result: fn(...args),
}
};
const add = recall((x, y) => x + y);
const getN = ({args}, n) => {
return args[n];
}
const res = getN(add(1, 2), 1);
console.log(res);
The above approach means that add() will return an object. To get the result of calling add, you can use .result. The same idea applies to get the arguments of add(). You can use .args on the returned object. This way of saving data is fine, however, if you want a more functional approach, you can save the data as arguments to a function:
const recall = fn => (...args) => {
return selector => selector(
args, // arguments
fn(...args) // result
);
};
// Selectors
const args = args => args;
const result = (_, result) => result;
const getN = (wrapped, n) => {
return wrapped(args)[n];
}
const add = recall((x, y) => x + y);
const wrappedAns = add(1, 2);
const nth = getN(wrappedAns, 1);
console.log(nth); // the second argument
console.log(wrappedAns(result)); // result of 1 + 2
above, rather than returning an object like we were before, we're instead returning a function of the form:
return selector => selector(args, fn(...args));
here you can see that selector is a function itself which gets passed the arguments as well as the result of calling fn() (ie: your addition function). Above, I have defined two selector functions, one called args and another called result. If the selector above is the args function then it will be passed args as the first argument, which it then returns. Similarly, if the selector function above is the result function, it will get passed both the args and the result of calling fn, and will return the result the return value of fn(...args).
Tidying up the above (removing explicit returns etc) and applying it to your example we get the following:
const foo = 'bar';
const hello = 'world';
const recall = fn => (...args) => sel => sel(args, fn(...args));
const returnFirstArgument = recall((val1, val2) => val1);
const returnArgumentByPosition = (fn, num) => fn(x => x)[num];
const returnSecondArgument = returnArgumentByPosition(returnFirstArgument(foo, hello), 1);
console.log(returnSecondArgument); // world
Side note (for an approach using combinators):
In functional programming, there is a concept of combinators. Combinators are functions which can be used as a basis to form other (more useful) functions.
One combinator is the identity-function, which simply takes its first argument and returns it:
const I = x => x;
Another combinator is the K-combinator, which has the following structure:
const K = x => y => x;
You may have noticed that the first selector function args is missing an argument. This is because JavaScript doesn't require you to enter all the parameters that are passed as arguments into the function definition, instead, you can list only the ones you need. If we were to rewrite the args function so that it showed all the arguments that it takes, then it would have the following structure:
const args = (args, result) => args;
If we curry the arguments of this function, we get:
const args = args => result => args;
If you compare this function to the K-combinator above, it has the exact same shape. The K-combinator returns the first curried argument, and ignores the rest, the same applies with our args function. So, we can say that args = K.
Similarly, we can do a similar thing for the result selector shown above. First, we can curry the arguments of the results selector:
const result = _ => result => result;
Notice that this almost has the same shape as the K combinator, except that we're returning the second argument rather than the first. If we pass the identify function into the K-combinator like so K(I), we get the following:
const K = x => y => x;
K(I) returns y => I
As we know that I is x => x, we can rewrite the returned value of y => I in terms of x:
y => I
can be written as...
y => x => x;
We can then alpha-reduce (change the name of y to _ and x to result) to get _ => result => result. This now is the exact same result as the curried result function. Changing variable names like this is perfectly fine, as they still refer to the same thing once changed.
So, if we modify how selector is called in the recall function so that it is now curried, we can make use of the I and K combinators:
const I = x => x;
const K = x => y => x;
const recall = fn => (...args) => sel => sel(args)(fn(...args));
const args = K;
const result = K(I);
const getN = (fn, n) => fn(args)[n];
const add = recall((x, y) => x + y);
const addFn = add(1, 2);
const nth = getN(addFn, 1);
console.log(nth); // the second argument
console.log(addFn(result)); // result of 1 + 2

Principle behind short callback function syntax

What is the principle behind this?
newArr.some(Array.isArray) === newArr.some(elem => Array.isArray(elem))
How is posible that they are parsed as equal?
I thought that newArr.some(Array.isArray) === newArr.some(Array.isArray()) (assuming that some is a loop and that JS assumed each val as the implicit arg of the func), but it's not. So, I'm confused. Please, help me.
Here, there are 2 applications of the cases above:
function flatMultiArr(arr) {
let newArr = [].concat(...arr);
return newArr.some(Array.isArray)
? flatMultiArr(newArr)
: newArr
}
console.log();//[ 1, {}, 3, 4 ]
function flatMultiArr(arr) {
let newArr = [].concat(...arr);
return newArr.some(elem => Array.isArray(elem))
? flatMultiArr(newArr)
: newArr
}
console.log();//[ 1, {}, 3, 4 ]
Note this question is not about how to flatten multidimentional arrays.
This principle is known as eta conversion. No, they are not "parsed as equal", they are different functions, but they behave the same, and therefore can be reasoned about equally. To simplify:
const f = Array.isArray
and
function f(x) { return Array.isArray(x); }
will have the same results when called1, i.e. f([]) or f(5).
1: In general, there are minor differences wrt to the this binding in the method and the number of arguments, but it works for Array.isArray.
Please note that callbacks are just functions. It is called eta-abstraction and makes your function slightly more lazy:
const fix = f => f(fix( f));
const fix_ = f => x => f(fix_(f)) (x);
// ^^^^ ^^^ eta abstraction
try {
const map = fix(go => f => ([x, ...xs]) =>
x == undefined
? []
: go(f) (xs).concat(f(x)));
}
catch (e) {
console.log(e.message);
}
const map_ = fix_(go => f => ([x, ...xs]) =>
x === undefined
? []
: [f(x)].concat(go(f) (xs)));
console.log(
map_(x => x * x) ([1,2,3]));

How to use lift if both function and arguments are “wrapped”

I’ve been trying to implement an Apply/Applicative type based on Javascript Functor, Applicative, Monads in pictures and the blog series Fantas, Eel, and Specification.
I think I’m making good progress, but I ran in to a case I couldn’t really find in any of the articles.
TL;DR Question
If lift2 is
f -> A.of(x) -> A.of(y) -> A.of(f (x) (y)) -or- A(y).ap(A(x).map(f))
what is the theory/name/type behind
A.of(f) -> A.of(x) -> A.of(y) -> A(f (x) (y)) -or- A(y).ap(A(x).ap(A(f)))
Introduction
I’m working with knockout.js, which gives me observable values. I’m trying to use them in a kind of functional fashion, extending them when needed.
First, I implemented map to make myself a functor:
ko.subscribable.fn.map = function(f) {
// note: calling without arguments is knockout's
// way of "unwrapping"
return ko.pureComputed(
() => f(this())
);
}
This allows me to do things like:
// "Pure" part describing my app
const myValue = ko.observable(2);
const doubleThat = myValue.map(x => x * 2);
// In- and output (IO?)
doubleThat.subscribe(console.log);
myValue(3); // Logs 6
Then, I ran in to the problem of working with functions that take multiple arguments. For example:
const filter = (pred, xs) => xs.filter(pred);
I solved my issues by implementing ap and currying my functions:
ko.subscribable.fn.ap = function(sf) {
return ko.pureComputed(
() => sf () (this())
);
};
const filter = pred => xs => xs.filter(pred);
With these changes in place, I can do:
const odd = x => x % 2 === 1;
const myPred = ko.observable(odd);
const myValues = ko.observable([ 1, 2, 3 ]);
const myFilter = myPred.map(filter);
const myResult = myValues.ap(filter); // S([ 1, 3 ])
The definition of lift2 gives me another way of writing the same thing.
const myResult = lift2 (filter) (myPred) (myResult)
So far, so good. I can use the dot-calls if the interim result is reusable, and a liftN call if I only care about the final outcome.
The problem
The liftN way of chaining one map with N - 1 calls to ap only works if I use plain functions. In my app however, I often deal with functions that are themselves wrapped in subscribables! For example:
const sum = x => y => x + y;
const mathStrategy = ko.observable(sum);
const v1 = ko.observable(2);
const v2 = ko.observable(3);
My attempts
Chaining works, but quickly gets very hard to understand.
// Ugly...
const myResult = v2.ap(v1.ap(mathStrategy)); // S(5)
I can use liftN, but only if I make sure my first function is id.
// Also ugly...
const id = x => x;
const myResultL = lift3 (id) (mathStrategy) (v1) (v2); // S(5)
My questions
If lift2 handles f -> A.of(x) -> A.of(y) -> A.of(f (x) (y)), what is the theory/name/type behind A.of(f) -> A.of(x) -> A.of(y) -> A(f (x) (y))
If such a thing does not really “exist”, would it be okay to write an implementation of ap that unwraps A(f) on the go? (i.e. f => ko.unwrap (f) (x))
Code example
Object.assign(ko.subscribable, {
of: function(x) {
return ko.pureComputed(() => x)
}
});
Object.assign(ko.subscribable.fn, {
map: function(f) {
return ko.pureComputed(() => f(this()));
},
ap: function(sf) {
return ko.pureComputed(() => sf () (this()));
},
toString: function() {
return `S(${JSON.stringify(this())})`;
}
});
// Example code:
const sum = x => y => x + y;
const mult = x => y => x * y;
const mathStrategy = ko.observable(sum);
const v1 = ko.observable(1);
const v2 = ko.observable(3);
const result = v2.ap(v1.ap(mathStrategy));
console.log(result); // S(4)
v1(2);
mathStrategy(mult);
console.log(result); // S(6)
.as-console-wrapper { min-height: 100% !important; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
Note: This is kind of related to a question I asked earlier. Back then, I was focusing on lazily unwrapping A(x) and A(y), which I have given up on by now 😉.
I think the question you meant to ask, with proper notation for the types, is
If lift2 handles Apply f => (x -> y -> z) -> f x -> f y -> f z, what is the theory/name behind Apply f => f (x -> y -> z) -> f x -> f y -> f z?
Such a function is rare, because everyone just uses ap or the respective infix operator, like in Haskell
let az = af <*> ax <*> ay
However, I saw some two references on the internet to it being called ap2 [1][2], which makes sense as it is analogous to lift becoming lift2.
You can write this helper function as
const ap2 = af => ax => ay => ap(ap(af, ax), ay)
or like you already did
const ap2 = lift3(id)

Create variable of arguments type

I'm trying to make middleware function lets call it debug, which should take some parameters, log them and pass to the next function:
const debug = (...args) => {
console.log(...args)
return args // will return array, not argument type variable
}
const compose = (...fns) => (...arg) => (
fns.slice().reverse().reduce(
(acc, fn) => !acc ? fn(...arg) : fn(acc), null
)
)
const f = x => x * x
const g = (a, b) => a + b
const makeMagic = compose(
f,
g,
debug
)
makeMagic(1, 2)
If I remove debug from composition everything works as expected, as soon as I place it at end, it breaks. Because it takes arguments but returns array.
I tried to rewrite debug this way:
function debug() {
console.info(arguments)
return arguments
}
But no way it fails.
A function always has only a single result value. You can't write a function that accepts multiple arguments and "returns" multiple values without some kind of container around them (like an array), it's just not a feature JavaScript has (nor do most other programming languages).
You can make debug a pure pass-through for a single argument, but not multiple. So for instance, you could make this work:
const result = debug(makeMagic(1, 2))
...where result would be the value makeMagic returned (after debug logs it), but you can't include it in the composed makeMagic the way you're trying to.
To have debug (or any other function) in the middle of a chain with your compose, you'd have to use a convention with it and all composeable functions about how they return multiple values, probably by having them all return an array. That also helps with the fact taht right now, your compose function has what I assume is a bug: It uses ...args any time a previous function returned a falsy value (0, "", NaN, null, undefined, or false), where I'm fairly sure you meant to do that only on the first call.
Here's a version of compose that expects composable functions, which are functions that return an array of their results:
const debug = (...args) => {
console.log(...args);
return args;
};
const compose = (...fns) => (...args) => (
fns.slice().reverse().reduce(
(acc, fn) => fn(...(acc || args)),
null
)
);
const f = x => [x * x];
const g = (a, b) => [a + b];
const makeMagic = compose(
f,
g,
debug
);
const result = makeMagic(1, 2);
console.log(result);

Is there a way to give curried arrow functions a type/tag?

Function encoded types (i.e. nested curried functions) have some drawbacks in Javascript:
Their representation in the dev console is obfuscated (e.g. [Some(5), None] is displayed as [f, f])
Nothing stops you from applying a combinator to the wrong type (e.g. eitherMap(f) (Some(5)))
You cannot inspect their free variables
You cannot even duck type them
These drawbacks render them useless in real world applications.
I was wondering if there is a way to overcome these shortcomings and came up with the following sketch:
const tag = (name, x, k) => {
const Cons =
Function(`return function ${name}() {}`) ();
Cons.prototype[Symbol.toStringTag] = name;
Cons.prototype["run" + name] = k;
Cons.prototype.tag = name;
const o = new Cons();
Object.defineProperty(o, "value", {get: () => x});
return o;
};
const Some = x =>
tag("Option", x, def =>
tag("Option", x, k => k(x)));
const None = tag("Option", null, def =>
tag("Option", def, k => def));
const option = def => k => fx =>
fx.runOption(def).runOption(k);
const safeInc = option(0) (n => n + 1);
safeInc(Some(5)); // 6
safeInc(None); // 0
const xs = [Some("foo"), None]; // [Option, Option]
/*
expanded dev console display:
1: Option {value: ...} --> expands to "foo"
2: Otpion {value: ...} --> expands to null
*/
Please note that I am not interested in prototypal inheritance at all.
This approach is both tedious and probably slow, because I apply the Function constructor, which makes the code less predictable. Is there a better way to give curried functions a type (or rather a tag in JS), so that the listed shortcomings are eliminated?
I slightly improved my approach and got rid of the Function call and the repeated creation of a constructor function. It's appropriate for my specific use case (function encoded types) but I failed to address the more general case of arbitrary functions in curried form, because it is still too tedious. Anyway, here it is:
const tag = Cons => (k, ...args) => {
const o = new Cons();
Object.defineProperties(o, {
"value": {get: () => args},
"runOpt": {value: k}});
return o;
};
const Opt = tag(
function Option() {
Option.prototype[Symbol.toStringTag] = "Option";
Option.prototype.tag = "Option";
});
const Some = x =>
Opt(def => Opt(k => k(x), x), x);
const None = Opt(def => Opt(k => def, def));
const option = def => k => fx =>
fx.runOpt(def).runOpt(k);
const safeInc = option(0) (n => n + 1);
safeInc(Some(5)); // 6
safeInc(None); // 0
Some(5); // Option {runOption}
[Some("foo"), None]; // [Option, Option]
/*
expanded dev console display:
1: Option {runOpt: f, value: ...} --> expands to ["foo"]
2: Otpion {runOpt: f, value: ...} --> expands to []
*/

Categories