8 ms·
Generalizing JSX: Delivering on the Dream of Curried Named Parameters
- draw_down 11y agoA certain portion of programmers seems convinced that currying offers a huge amount of power, and we just haven't unlocked it yet. But I don't think I understand why they feel that way.
- darawk 11y agoIt mostly allows you to write extremely short code. E.g. `sumList = reduce(sum)` It has a variety of drawbacks though, like being harder to inspect at runtime, and arguably harder to read.
- tolmasky 11y agoYup, couldn't agree more and that's exactly one of the concerns I'm trying to address in the blog post ("All in all, the resulting effect in my exprience is that currying makes writing code far more pleasurable, but often makes reading code somewhat confusing."). I think the combination of named parameters actually makes it more readable.
- e_d_g_a_r 11y agoit offers some elegance, here's a timeout function blogpost. http://hyegar.com/2016/03/22/simple-timeouts/ http://hyegar.com/2016/03/22/simple-timeouts/ In it the timeout function only takes one arg for its timeout wrapped function, so how do we use functions with more than 1 arg? Via currying
- k__ 11y agoIt's just a different way of structuring. api = new Api('http://my.cool.api' http://my.cool.api') api.get('/it') api.post('/it') // connect = rootUrl => method => endpoint api = connect('http://my.cool.api' http://my.cool.api') get = api('GET') post = api('POST') get('/it') post('/it')
- pka 11y agoCurried: map (f . fst) Uncurried: \xs -> map (\x -> f (fst x)) xs Now comparing this to js would just be unfair (edit: ES6 lambdas are probably ok).
- e_d_g_a_r 11y ago"Dream of Curried Named Parameters" What dream, this is a daily reality in OCaml.
- tolmasky 11y agoYeah definitely an inspiration (and mentioned twice in the blog post). The main differences (unless I'm mistaken), are the parameter name mapping (which make it easy for differing APIs to interact well) and the idea of separating function application from argument binding, which allows for both re-currying (which actually unifies default parameters under curried parameters) and also for leaving fully-curried functions in a callable state.
- WorldMaker 11y agoThis is a good post with a lot of ideas to stew on. I think my only criticism of the current approach in the linked GitHub repo [1] is the use of `eval`, as that could make it tough to utilize in low security/sandboxed environments such as mobile apps and CSP-controlled sites. I'll save attempting an actual code exercise for later, but my first thought was maybe using JS implicit `this` to your advantage (even while trying to stray away from classes) and using `this[functionName]` to index into it. (You'd still have security concerns with `this` defaulting to `window` or `global`, but you'd avoid the need for `eval` and you can take advantage of the depth of abilities of constructor functions and ES2015 class syntax.) [1] https://github.com/tolmasky/generic-jsx https://github.com/tolmasky/generic-jsx
- tolmasky 11y agoYeah the use of eval is purely to get it working today. The ideal would be to just change the JSX parser to place whatever is in the JSX tag directly. That would also give you arbitrary expressions: <memoize(f) key = "value"/> <compose(f,g) key = "value" /> If you look at the implementation in the repo, you'll see its actually a little more complex than just eval now (since JSX will pass the actual reference when the tag name starts with a capital letter), but again this was solely to provide something that people could use with their existing Babel implementations and a simple require.
- kbenson 11y agoCouldn't you get around using eval by just use an object and register methods on it, instead of global functions, essentially using the object as a namespace? Instead of /* @jsx ((a,b)=>(eval(a)(b))) */ You would have /* @jsx ((a,b)=>(MyJSX[a](b))) */ And then just build your functions on top of the MyJSX object?
- WorldMaker 11y agoYep, that's essentially where I was leading.
- tobr 11y agoI think you mixed some nice ideas with a very weird idea for no good reason. I kept looking for why you want to do this through JSX, but I just didn't find anything convincing. I like the idea of using the "from" function to rename applied parameters. But that and everything else would be equally possible and a lot less confusing if it didn't involve JSX, no?
- tolmasky 11y agoJSX provided a convenient syntax to have named parameters in JavaScript. Additionally, it results in nice data structure literals, and finally, you get the same benefits "for free" in a React app by doing this. The main thing here was that through thinking about JSX, I was able to reach these conclusions. If I had not had to work with this separate syntax, I may not have tried separating function application from function binding. It's kind of like how when you give something a word you can think about it clearer. For example, one of the issues thats frustrated me in the past is wanting to fully-curry a function but still have it be callable. For example, if you have id = x => x, if you could curry it it would simply become an "always" function. So like, [...].map(<id x = {5}>) (this maps everything to 5 in our case). But with traditional currying, that would simply return 5. Again, you could achieve this curry(id, {x:5}), but I like the visual queue that JSX syntax gives you saying "This is a new FUNCTION with these parameters".
- malekpour 11y agoVery good article, it is easy to predict great use cases for JSX concept in the future. I proposed the idea of using JSX as angular2 templates. They didn't like it and I think the React competition was an important factor for that. https://github.com/angular/angular/issues/5131 https://github.com/angular/angular/issues/5131
- robwormald 11y agoHeh, not exactly. We have a finite amount of hours in the day, and maintaining a JSX implementation is something we just aren't really interested in. You're more than welcome to implement such a thing yourself though, and I'd be the first to retweet it if you did.
- rook2pawn 11y agoVery relevant https://github.com/substack/hyperx https://github.com/substack/hyperx I code in react without jsx and webpack. I recommend hyperx for your code. Hopefully new modules can be built out of this one.
- tolmasky 11y agoIn case anyone is curious, I have since posted some additional thoughts: 1. Unifying default parameters with curried named parameters: https://tonicdev.com/tolmasky/default-parameters-with-generic-jsx https://tonicdev.com/tolmasky/default-parameters-with-generi... 2. Using generic JSX to declaratively specify JavaScript ASTs: https://tonicdev.com/tolmasky/generic-jsx-for-babel-javascript-ast https://tonicdev.com/tolmasky/generic-jsx-for-babel-javascri...
- agumonkey 11y agoSeeing 'xml' trees reminds me of a child from ML and XSLT...
- zeckalpha 11y agoXQuery?
- DougBTX 11y agoRegarding the hack to make function calls: if JSX elements start with a capital letter, then the pragma is ignored, and the element name is used as a local variable name instead, e.g.: transform("<Foo id = 'my-element'>hi!</Foo>") outputs Foo({id: "my-element"}, ["hi!"])
- tolmasky 11y agoYeah, it was outside the scope of this blog post, but if you look at how its implemented here: https://github.com/tolmasky/generic-jsx/blob/master/generic-jsx.js#L9 https://github.com/tolmasky/generic-jsx/blob/master/generic-... you'll see it deals with both cases.
- Bjartr 11y agoDoes this go far enough that we can invoke Greenspun's Tenth Rule? > Any sufficiently complicated [Javascript] program contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of Common Lisp. https://en.wikipedia.org/wiki/Greenspun%27s_tenth_rule https://en.wikipedia.org/wiki/Greenspun%27s_tenth_rule
- batspace 11y agoDefinitely on the road to Greensunning, but nowhere near half of CL
- smrq 11y agoUltimately, isn't this just saying "currying might be great if it was syntactically different from function calls"? JSX is just a hack to make that happen with today's JavaScript tech... It feels like a red herring to focus on it.
- justno 11y agoThis is beyond ridiculous. I fucking hate everybody.
- mcintyre1994 11y agoFYI, your tonicdev code runner doesn't seem to be working for me. Whenever I run a code example, I get 5 403 errors one after the other trying to make PUT requests to http://tonicdev.com/new http://tonicdev.com/new Sample request: {"model":{"content":{"package":{"engines":{"node":"4.x.x"},"lastEvaluatedDependencies":{},"dependencies":{}},"title":"","cells":[{"_id":"cells/3f4e1137-79ee-4dbd-b201-ba404a056e0f","content":{"type":"source","text":"/* @jsx console.log */\n\n// Now this is the same as console.log(\"div\", { \"id\":\"my-element\"}, \"hi\");\n<div id = \"my-element\" >hi</div>"}},{"_id":"cells/fd8deede-cfeb-48df-ac0f-740397f61e47","content":{"type":"rich-text","text":"Created from: http://tolmasky.com/2016/03/24/generalizing-jsx/","tag":"p"}}] http://tolmasky.com/2016/03/24/generalizing-jsx/","tag":"p"}...},"evaluationCount":0},"fromNotebook":null,"fromLocation":"http://tolmasky.com/2016/03/24/generalizing-jsx/","embed":true http://tolmasky.com/2016/03/24/generalizing-jsx/","embed":tr...} And response: { "message": "CSRF token failure", "csrf": "4fa7f4dc-c906-4561-92dd-2489cc53c7f7" } Safari on OSX, Chrome doesn't have the problem.