raganwald / raganwald.github.com Goto Github PK
View Code? Open in Web Editor NEWraganwald.com jekyll source
Home Page: http://raganwald.github.com
raganwald.com jekyll source
Home Page: http://raganwald.github.com
Hey Reginald!
I've been reading "Why Y? Deriving the Y Combinator in JavaScript" with great pleasure. I was somewhat familiar with the concepts, but following through really helped them click. Thank you!
My process of understanding did involve tinkering with some code, and it seemed to me that the code for the various combinators was at times less simple than it could have been.
For instance, your formulate the why bird as:
const why = fn =>
(
maker =>
(...args) => fn(maker(maker), ...args)
)(
maker =>
(...args) => fn(maker(maker), ...args)
);
Why not opt for the more intuitive:
const why = fn =>
{
const wrapper = (...args) => fn(wrapper, ...args);
return wrapper;
};
I do understand the interest of presenting the first one, it does help with understanding the classical approach based on lambda-calculus which enables recursion without names (the real mind-bender here), but I'd much rather have the second one in my actual code!
In fact, I found it easier to understand the anonymous version by working backward from the version that uses the wrapper
binding.
You do say that of a combinator that "It cannot create a named function expression." and "It cannot declare any bindings other than via parameters." But since you relax some other requirements for the idiomatic version, surely those could be relaxed too in practice.
The difference is even more dramatic regarding the long-tailed widowbird/trampoline:
const longtailed =
fn =>
(...initialArgs) => {
let value =
(x => x(x))(
maker =>
(...args) =>
fn((...argsmm) => new Thunk(() => maker(maker)(...argsmm)), ...args)
)(...initialArgs);
while (value instanceof Thunk) {
value = value.evaluate();
}
return value;
};
My simplified version:
const longtailed = fn => (...args0) =>
{
const wrapper = (...args) =>
new Thunk(() => fn(wrapper, ...args));
let value = fn(wrapper, ...args0);
while (value instanceof Thunk)
value = value.evaluate();
return value;
};
Finally, a question, just to be sure I understood correctly. You write:
Let’s begin our cleanup by moving Thunk inside our function. This has certain technical advantages if we ever create a recursive program that itself returns thunks.
Do you mean that we want to distinguish the thunks returned by a why-form function passed to to the trampoline from the thunk that the trampoline uses internally?
Thanks again, and cheers!
http://raganwald.com/2015/06/04/classes-are-expressions.html
function Person (firstName, lastName) {
var API; return API = { // could be in two lines, but i use this pattern all the time
fullName () {
return firstName + ' ' + lastName;
},
rename (first, last) {
firstName = first;
lastName = last;
return API;
}
};
}
I enjoy reading your writing.
Please continue, even if you feel that you keep saying the same things: Repetitio mater studiorum est
Here are a couple of spelling errors.
This appears to work: By prepending the exiting edits onto edits being appended to a buffer, we transform the new edits to producet the same result, synchronizing the buffers.
producet -> produce
And if we put aside the problem of user experience, we have a very string takeaway from dealing with maintaining the future while inserting new edits into the history.
string -> strong ?
I know you removed your twitter account so figured you would want to know this link was still on your site.
Could you not have used generators in http://raganwald.com/2015/02/17/lazy-iteratables-in-javascript.html ?
As I tried to explain myself the foreign concepts of iterables, in the new ES6 syntax, I wrote this line-by-line explanation of what 'mapIterableWith` was doing.
// mapIterableWith
// Accepts a function to map, and an iterable, and...
// returns an object which...
// under the conventionally defined key, contains a 'generator' function which...
// returns an iterator-looking object whose 'next' method...
// returns an object {done: bool, value: fn(x)} for each value in the passed iterable...
// until the passed iterables' end...
const mapIterableWith = (fn, iterable) =>
({
[Symbol.iterator]: () => {
const iterator = iterable[Symbol.iterator]();
return {
next: () => {
const {done, value} = iterator.next();
return ({done, value: done ? undefined : fn(value)});
}
}
}
});
But I feel like it was really micro-managing what's going on, rather than encapsulating alot of that semantics in a function with a *
part of its name where the behavior is more implied.
// mapIterableWith
// Accepts a function to map, and an iterable and ...
// returns a generator which yields values ...
// of the passed function applied to the values of the iterable
const mapIterableWith = (fn, iterable) =>
({
[Symbol.iterator]: function* () {
const iterator = iterable[Symbol.iterator]();
yield fn(iterator.next().value);
}
});
Am I missing something ?
Found a typo in /2020/05/03/fractran.html
:
It reads "If we one of them", but should read "If we program one of them".
In Functional Mixins in ECMAScript 2015 you go from a simplified approach based on Object.assign
, and you end up with a more complex approach based on descriptors.
However, Object.assign
by specifications copies enumerable
properties values, and also Symbols
, while your proposed final code ignores Symbols completely.
Either you didn't want to have Symbols usable for mixins, or you forgot to set them too as descriptors.
Accordingly, your final code needs an utility like the following one, if the purpose was to match the original Object.assign
intent plus enumerability:
function assignWithEnumerability(target, source) {
return Object
.getOwnPropertyNames(source)
.concat(
Object.getOwnPropertySymbols(source)
)
.reduce(
function (target, key) {
return Object.defineProperty(
target,
key,
{
enumerable: Object
.getOwnPropertyDescriptor(
source,
key
).enumerable
,
value: source[key]
}
);
},
target
)
;
}
So it can do the meant thing in the right way:
function FunctionalMixin (instanceBehaviour, mixinBehaviour = {}) {
const typeTag = Symbol("isA");
function mixin (target) {
assignWithEnumerability(target, instanceBehaviour);
target[typeTag] = true;
return target;
}
assignWithEnumerability(mixin, mixinBehaviour);
mixin[Symbol.instanceOf] = (instance) => !!instance[typeTag];
return mixin;
}
eventually you can make the suggested utility more suitable for your intents having an extra boolean argument that lets the function consider or not enumerability.
In this example there is a Uncaught ReferenceError: trampoline is not defined
function factorial (n) {
var _factorial = trampoline( function myself (acc, n) {
return n
? function () { return myself(acc * n, n - 1); }
: acc
});
return _factorial(1, n);
}
factorial(10);
//=> 362800
factorial(32768);
//=> Infinity
Please disregard
Loved reading your post, though some of the code samples are a little confusing just looking at.
class BankAccount
def initialize options = {}
self.extend(
if options[:frozen]
Frozen
else
Thawed
end
)
end
end
Could be written as
class BankAccount
def initialize options = {}
if options[:frozen]
self.extend(Frozen)
else
self.extend(Thawed)
end
end
end
Just thought this reads a little nicer. To each his own I guess.
The article resumes to "classes are wrong because they are difficult to modify". But this issue is also observable in classical programming languages like C where functions call other functions. It will be easier to understand your point of view if you give some examples on how we should replace classes while avoiding "spaghetti code", enabling auto-completion, enabling type checking, ...
In your article "time-space-life-as-we-know-it", it seems their is a typo:
const neighboursOfUrLl = (square) => [
square.ul.ur, square.ur.ul, square.ur.ur, square.ur.lr,
square.lr.ur, square.lr.ul, square.ll.ur, square.ur.lr //repeated declaration
];
neighboursOfUrLl(sq).join('')
//=> "1237BA97"
Should be:
const neighboursOfUrLl = (square) => [
square.ul.ur, square.ur.ul, square.ur.ur, square.ur.lr,
square.lr.ur, square.lr.ul, square.ll.ur, square.ul.lr
];
neighboursOfUrLl(sq).join('')
//=> "1237BA95"
Btw: amazing article, really great job, thanks a lot!
const compositionOf = (acc, val) => (...args) => val(acc(...args));
should it be:
const compositionOf = (acc, val) => (...args) => acc(val(...args));
or just that ?
thanks for your good article.
Using this site while holding an iphone horizontally was a brutally poor experience. Something about how the site handles the zoom/viewport made it impossible to get the entire width of the main text column into the view at once so you had to pan side-to-side. Really rough.
It could be done dynamically like:
let String.prototype.reverse = function (...) {...};
'abc'.reverse()
getString().reverse()
In second example JavaScript implementation can't know statically whether getString()
will return string, but it will now when it will get to it. This is actually better than ::
cause you can polymorph:
let String.prototype.reverse = function (...) {...};
let Array.prototype.reverse = function (...) {...};
// ...
something.reverse()
The key idea is that extension is lexically scoped so that it won't affect any random code. Also, you most surely will want to import/export this extensions so my primitive syntax might not work, but this is only syntax issue.
There are actually a corresponding feature in ruby 2.0 and a perl module for this.
The site is missing IPv6 support and thus is inaccessible to people on IPv6-only networks. Furthermore, people on dualstack IPv6-optimized networks will experience slower connections than they would with IPv6 support.
Hi,
I was reading http://raganwald.com/2015/02/07/tail-calls-defult-arguments-recycling.html, and it's fascinating stuff, thank you.
However, I was doing some testing myself, and I found that the tail call version of length()
still hits Maximum call stack size exceeded
at ~ 8,400 item long arrays on my Macbook Pro
Is this because of the inefficiency of [first, ...rest]
. My understanding of the article was that the recursion was now ok because JavaScript optimizes away the function call overhead and stack space.
I'm just finding both the tail call length
and the inefficient one fall over at the same point:
const length = ([first, ...rest], numberToBeAdded = 0) =>
first === undefined
? numberToBeAdded
: length(rest, 1 + numberToBeAdded)
the link much much more
at the bottom of https://github.com/raganwald/raganwald.github.com/blob/master/_posts/homoiconic/2013-02-10-prototypes.md / http://raganwald.com/2013/02/10/prototypes.html is broken 😘
Hi Reginald;
Thanks for the excellent article. It brought this picture to mind:
An alternating current, personified as a human moving steadily along some circuit (life's patterns are hard wired after all) flipping between professional and student at each increment.
I think as professionals in an industry that emerged rather than being defined we're still trying to define an objective balance between the two. The lack of definition is responsible for the fogged dialogue that usually accompanies knowledge expeditions. And why the same questions are asked over and over.
My 2cents =)
This issue however is about a small spelling issue:
One of the most important ways to learn something [s/it/is] to experiment
This generally looks pretty good. Ihave just a couple thoughts:
Might be worth mentioning that some languages (but not Snmalltalk, Ruby, JS, CL, etc.) treat class as nominal types.
classes: In Smalltalk and Ruby classes aren't just first class "entities" they are first class objects.
prototypes are not classes:
object-orient programming can mean almost anything: I think it does have a single core meaning (at least to classic OOP programmer): structuring programs in terms of the protocols of sets of communicating entities (objects)
the JavaScript approach: I'll argue that ES6 classes are as "first class" as the classes of Smalltalk or Ruby. The fisrt class valued of an ES6 class definition is simply a constructor function so an ES^ "class" is nothing more than a first class function object that follows a particular structural pattern that relates it to a prototype object, its "superclass", and its instances.
I really enjoyed Anamorphisms in JavaScript, thanks for taking the time to share your insights. Since we still don't have tail recursion in JavaScript, I wrote this silly iterative unfoldWith
- actually, I wrote it because it was fun :). The generator approach was elegant as well, here's my unfoldWith
.
const unfoldWith = (fn) => (initialValue) => {
const accum = [];
const stack = [initialValue];
while (stack.length > 0) {
const value = stack.pop();
const {result, next, done} = fn(value) || {done: true};
if (done) {
continue;
}
accum.push(result);
stack.push(next);
}
return accum;
}
Silly example usage:
const rangePositive = (start, end) => unfoldWith((x) => x <= end ? {result: x, next: x + 1} : null)(start);
rangePositive(-2, 2) // [ -2, -1, 0, 1, 2 ]
const rangeNegative = (start, end) => unfoldWith((x) => x >= end ? {result: x, next: x - 1} : null)(start);
rangeNegative(2, -2) // [ 2, 1, 0, -1, -2 ]
function * downToOne(n) {
for (let i = n; i > 0; --i) {
yield i;
}
}
[...downToOne(5)]
//=> [ 1, 2, 3, 4, 5 ]
The array should be [5, 4, 3, 2, 1]
I've read your interesting article about Transducers and I've posted a question on SO.
I'm sure you could help answering this.
By the way, this is a gist with C# porting
Does it work? Let's find out!
just testing, man
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.