9 ms·
The Misunderstood Roots of FRP
- emmelaich 7y agoFor the author - it's "Salon de Refusés" not refuge. i.e. "exhibition of rejects" https://2019.programming-conference.org/track/sdr-2019-papers https://2019.programming-conference.org/track/sdr-2019-paper...
- macintux 7y agoFascinating content. As someone burdened by working in a wildly non-denotative language (Python) but who would love to return to functional programming someday, the vision is very appealing. I like FP because it allows me to be lazy; quoting the author: > A denotative language resembles a dictionary or encyclopedia, where one can understand an entry by reading it and what it references. A non-denotative language resembles prose, like a novel, which you have to read cover-to-cover to know what happens, even if you only care about one specific character.
- jonstewart 7y agoWhat’s FRP?
- rbobby 7y agoI had the same question. Functional Reactive Programming.
- vortico 7y agoThanks. I'll recite the rule of acronyms and articles: Always define all acronyms in your article.
- blondin 7y agoyep. i knew in our field the F & P could only mean functional programming. but the R eluded my acronym decrypting skills. glad to find someone found what it meant. i almost thought it was "recursive"... can we agree to stop using these meaningless acronyms?!
- gtirloni 7y agoYou just have to spell it out once at the beginning of the article, then it's fine. The author never did it once.
- iamwil 7y agoThe site is "Future of Coding". He assumed most of his audience were language wonks, and you don't have to go far to run into FRP. That said, it's best not to assume.
- pubby 7y agoYeah okay. Then why does nobody use it? Even languages like Elm ditched it for easier to understand concepts. Let's face it. FRP kinda sucks. It's awkward as hell to use and takes way to many brain-cells to achieve simple results. Even the experts have trouble with it. I remember e-mailing the author of a popular FRP library once asking him how I could get multiple shapes moving on the screen at once (as opposed to just one). He replied that he had no idea. Apparently it was still an open problem he was working on. Yikes! State turns out to be a convenient, natural way to represent... state. Funny, isn't it? That if you have some real world problem that involves state, that you want to model that using virtual state and not the high-order time-varying continuous functions that FRP uses. Even Alonso Church admitted that Turing's tape-based model of computation was easier to understand than his lambda calculus. BTW one more thing. Spreadsheets are commonly cited as a good example of real-world FRP use. The great irony is that nobody on the planet thinks of spreadsheets as time-varying continuous functions. Nope. People view spreadsheets as a big grid of numbers... i.e. state.
- proc0 7y agoIsn't Redux FRP? You can easily do the basics in React as well. I would say it's the dominant paradigm in UI development and most don't know they're using it.
- pubby 7y agoTo me, the core of FRP is hiding state. You couldn't look at a FRP program and say, "Yeah, here's where we define value X". Instead, you'd see various time-varying functions and the manner in which these functions are composed will implicitly define the state. I think Redux isn't true FRP because it's very much about defining state. You plainly state every variable your program needs, while in FRP, variables just don't exist.
- proc0 7y agoHiding state is more the priority of declarative programming. FRP being declarative definitely does that, but I think the update loop is what's at the core of FRP, namely function changes over time and how they compose together to create chains of function changes over time, or something like that.
- dustingetz 7y agoWhat Steve calls "Denotative Continuous-Time Programming" – I think Clojurists call this declarative data programming – that is, you figure out a way to model the problem domain in data, and then write pure functions on that data. For example, React.js models the dom as data. Clojure gives you the toolkit of programming language primitives you need to do this easily, ergonomically and often, for all of your problem domains, not just virtual dom. I think an example of database programming in "Continuous Time" would be (datomic.api/q '[:in $ :find ?e :where [?e :post/title]] db) where `db` is a time-pinned and consistent value of the database graph – in other words datomic.api/q is a conceptually pure function of time, time is a parameter, which implies you can rewind it or speculate into the future (both of which are supported by this interface) As for abstracting HTTP – what if you considered network io as just a way to lazy load a cache of immutable database values? So for example, this would work a bit like Git – we don't care how the clone protocol works, just load me the file values I identified. Maybe it uses HTTP, maybe it uses something different, who cares? Get me the value I asked for in the fastest way possible given available infrastructure, distributed caches, etc. Then, the question of IO resolves to: what categories of effects can be modeled as values and functions on values? Given declarative data programming in Clojure – basically anything!
- skybrian 7y agoYou can think of a timeline as immutable, but you don't know values from the past unless you arranged for them to be recorded, you don't know values from the future until they happen, and you don't know what's going on at any other node unless they send you a message about it and it eventually makes it across an unreliable network. (So, sometime after it actually happened.) If you model this in a declarative way then you have to be careful to avoid implying that all events should be remembered, and also avoid depending on anything in the future unless you want to wait for it. This makes designing an intuitive FRP-based language pretty hard.
- dustingetz 7y ago> be careful to avoid implying that all events should be remembered Is that true in a post-AWS world with storage getting cheaper faster than you can consume it? Maybe don't put 4k video in the log. But, you're right, we can stream, shard and forget as necessary. > also avoid depending on anything in the future unless you want to wait for it Can you elaborate on this, my gut reaction is to ask why I need to avoid depending on git commits that haven't been written yet – it's kind of a weird question right? Time is explicit now, which means you have the right knobs you need to coordinate it, even across distributed nodes.
- skybrian 7y agoSaying that expressions independently denote a value is misleading. You can't know what an expression means without knowing the definition of each symbol it uses, and those symbols come from the expression's environment. These symbols may be defined in terms of other symbols, in turn, and the dependency graph of a large program is by no means simple. Examples that use well-known mathematical functions give a misleading impression that such expressions will be easy to understand. Instead, it can become like puzzling over the meaning of the equations in a mathmatics paper. As the author discovered, this isn't always easy, particularly for unfamiliar mathematical objects, and it tends to appeal more to people with a background in mathematics. Also notice that the focus on the value of an expression hides all performance issues. Maybe we can specify what an animation should do, but that doesn't mean it will run smoothly. It can be valuable to cleanly separate so-called "correctness" from performance (as if a program that's too slow is somehow correct?), but this doesn't relieve the programmer of the responsibility to work on performance. Languages that don't give you the tools to control performance are incomplete.
- dmitriid 7y agoAs with most if these things, the theory is fascinating. And then comes a contrived small code example... and the theory falls apart: - the example is trivial - the code example is extremely complicated for such a trivial example - the code has to be explained in minute detail, with at least one visualization (better, two) - and it still remains largely over complicated I shudder to think of any non-trivial example with this approach. It will hardly be more comprehensible than existing RxJS or Redux code.
- macintux 7y agoAnd the author admits as much: > Even I find the above code hard to read, despite having written it! While this could be seen as a downside of the denotative approach, I see it as a mismatch between the denotative approach and textual syntax. Clearly, from this piece and his site as a whole, he’s looking at the long-term picture. Maybe there’s no way to make this better, but we’ve been stuck with the same basic models for decades. I’m glad people are looking for more revolutionary ways to make programming more powerful.
- zenhack 7y agoI kindof wonder if this isn't one of those things that falls flat because it's a toy example, and anything but the most direct approach is going to look clumsy and over-engineered. I've spent a bunch of time working in Elm, though I hadn't used it in anger before they dropped the FRP stuff. My experience with post-frp Elm is that: * It seems really elegant on small examples * When you start working with larger codebases, and you have some resuable UI elements you want to build, you end up writing a lot of "routing" code to shunt messages to sub-components. Conventional wisdom in the community is to try to keep app structure as "flat" as you can to avoid this, but I've not seen a codebase of meaningful size where this doesn't happen enough to be annoying. I have a gut instinct that "real FRP" might shine a bit more at this point; it seems like it would make wiring together different bits of the UI easier.
- csande17 7y agoImagine you were trying to explain the temperature-conversion program's behavior in the simplest, clearest way possible. (That is, after all, what programmers fundamentally do: try to explain things to computers as simply and clearly as possible.) You'd probably say something like: "When the user changes the Celsius textbox, the computer changes the Fahrenheit textbox to the converted value." And indeed, that's the program most people would write: celsiusTextbox.whenChanged do fahrenheitTextbox.value = cToF(celsiusTextbox.value) end What you wouldn't say is something like: "The Fahrenheit textbox's value depends on whether the Fahrenheit textbox or the Celsius textbox was edited more recently. If the Fahrenheit textbox was edited more recently, its value is equal to the value the user entered into it most recently. If the Celsius textbox was edited more recently, the Fahrenheit textbox's value is equal to the converted value of the value the user entered into the Celsius textbox most recently." But that's the program you have to write in the "DCTP" approach proposed by the author. I think this is true of a lot of UI programming: most people intuitively think about it in terms of "when X happens, do Y", so trying to cram it into another programming model is more trouble than it's worth.
- _bxg1 7y agoYeah. More power to people like this who are trying to make pure-functionalism more accessible and practical, but I have my doubts that contorting logic that's naturally stateful into a denotational paradigm will ever feel natural or intuitive. Human intuition is rooted in navigating the physical world, and imperative/cause-and-effect thinking is a very physical way of accomplishing things.
- throwaway_n 7y agoWon't your example trigger an infinite loop of celsius/fahrenheit conversions? Especially if the floating point value is slightly off. I think your example is exactly why stuff like React won vs data-binding frameworks. With declarative programming, you just have a single source of truth that you change once (you can arbitrarily pick celsius or fahrenheit or even kelvin) and let the framework figure out what needs to be diff-ed in the derived views.
- 7y ago
- zyxzevn 7y agoNobody quickly understands: A(B(C(D(E(x))))) That is why they use the assignments. e= E(x) d= D(e) c= C(d) b= B(c) a= A(b) But many people can understand: x-> E -> F-> C-> B-> A // where -> is a pipe operator. Now you see that you first execute E with x as input. This shows that Functional program has some kind of problem, if it is not presented in a good way. There are also other problems. The overuse of Currying is bad, as it hides what is going on. Then we can also have recursion mixed with lazy execution. I think that the problem with functional programming is the bad presentation of what is really going on. I try to overcome these problems by using a pure graphical system instead. Everything should be as simple and clear as possible. The system is still in design/development, but you can see some at http://www.reddit.com/r/unseen_programming/ http://www.reddit.com/r/unseen_programming/ The general idea is that cells like in a spreadsheet are a basis for our functions. Unlike a spreadsheet-cell they can contain multiple variables. These cells can then be combined with pipes and streams. That may already define an functional language, but for me that is just the start.
- pasquinelli 7y agoThe first line seems the most easily parsed to me. The second one is the worst, and the third one only works for a tidy pipeline; if you have to combine multiple pipelines you'd need to bracket them, as in the first.
- jcelerier 7y ago> The first line seems the most easily parsed to me. The second one is the worst, and the third one only works for a tidy pipeline; I'd take the second over the other ones any time of the day, which clearly shows that there is no actual problem to solve here : we all see the world differently and there's nothing anyone can do about that.
- heavenlyblue 7y agoThe first line makes it hard to parse actual diffs in git.
- zyxzevn 7y ago
- perl4ever 7y agoI notice the mention of spreadsheets. Something I never thought about until I started writing scripts in Excel is that when you define new functions to be used in cell formulas, they are not allowed to have side effects...and it didn't take long before I wanted to write functions with side effects. Sure, this makes sense from a certain perspective, but when you're using a dialect of Basic, you kind of think it's down and dirty, anything goes. I mean, this is the language that used to usually have "peek" and "poke".
- falcor84 7y agoFor better or worse, Google Sheets functions (written in App Script) are allowed to have side effects. Though when invoked in cells, you don't have full control over when they're actually recalculated (there seems to be complex caching), so you need to plan your side effects accordingly.
- keithalewis 7y agoIf you use Microsoft's C SDK then you can write functions with limited side effects by declaring the function "uncalced". For example, you can peek at the current cell value of the function being called.
- mathgladiator 7y agoThe problem here is FRP is still immature and produces too much toy-ness. I've done some work in space, but the core of it is that the techniques are too expensive at the moment. This expense manifests in poor capacity utilization in the data center, and poor battery usage in mobile devices.
- aryehof 7y agoI have long thought that the Nygaard definition of a functional program was correct, but largely misunderstood. "A functional program is regarded as a mathematical function, describing a relation between input and output." I think this article is helpful in explaining how insightful that definition is. It's interesting to contrast that with his other classifications of major paradigms at that time. Particularly that of an Object Oriented program (he is one of the fathers of OO with Dahl), which is at odds with the modern viewpoint today ... 1. ProceduralProgramming. A program execution is regarded as a (partially ordered) sequence of procedure calls manipulating variables. 2. ConstraintProgramming. A program is regarded as a set of equations describing relations between input and output. 3. ObjectOrientedProgramming. A program execution is regarded as a physical model, simulating the behavior of either a real or imaginary part of the world.
- sriku 7y agoThis stuff is close-to-heart for me as FRP (and Elliott's work in general) greatly inspired my thinking over the years. Here are a few instances where the drive to be denotational in api design led to very satisfactory results. This is a massive "shameless plug" post, but I justify it as a dedication to Conal Elliott. First, a couple of old talks on the topic - - "Functional thinking" - Brings together some of the thinking I've applied in a few areas - http://sriku.org/blog/2015/08/11/talk-functional-thinking-for-fun-and-profit/ http://sriku.org/blog/2015/08/11/talk-functional-thinking-fo... . - "Beta abstraction for bottom-up theory building" - Shows how beta abstraction can be applied to systematically become denotational - http://sriku.org/blog/2016/02/06/beta-abstraction-for-bottom-up-theory-building/ http://sriku.org/blog/2016/02/06/beta-abstraction-for-bottom... Systems - - In "muvee Reveal", an automatic video production system, the styles are written in a Scheme-dialect called "muSE"[1] in which stuff needed to represent stylistic elements are built. The editing styles DSL [2] and documentation show how this stuff can be represented well removed from implementation details. (Disclaimer: I used to work for muvee, but no longer do so stuff may have changed.) In particular, video and animations were not modeled as functions of time to Image, but functions of a time interval [t,t+dt] to Image. The reasoning was that the interval information is critical to render motion blur. You could argue that the "dt" is a detail that can be passed on later at render time, but it didn't take away much from the API's simplicity. - Steller[3] - a library for declaratively composing dynamic temporal structures, useful (and used) for music and synchronized animations. - elm-anima[4] - a concept demo of structuring animations in Elm. This was pre-18 and so doesn't use subscriptions. Here, animations are conceived of as processes rather than functions over time. I've described the thinking in a post [5]. Elm fell out of favour for me as there were many APIs I needed to work with that I couldn't use it with and the portion that needed Elm was small in the systems I was working with. [1]: https://github.com/srikumarks/muSE https://github.com/srikumarks/muSE [2]: https://srikumarks.github.io/muvee-style-authoring/ https://srikumarks.github.io/muvee-style-authoring/ [3]: https://github.com/srikumarks/steller https://github.com/srikumarks/steller [4]: https://github.com/srikumarks/elm-anima https://github.com/srikumarks/elm-anima [5]: http://sriku.org/blog/2015/12/13/towards-reactive-animation-in-elm/ http://sriku.org/blog/2015/12/13/towards-reactive-animation-...
- iamwil 7y ago
- tsimionescu 7y agoThe author comments often that there are certain concepts that 'belong in the implementation, not the surface', such as explicit sequences of operations and any interaction with the outside world. I believe that this relegates DCTP to the status of a domain-specific language, not a general programming approach: if we know from the start that there are certain computations that we can't/don't want to perform with DCTP, then we know from the start that it only applies to certain domains of programming. This isn't a problem in itself of course - DSLs can be wonderful things. But this can become a problem if you haven't taken the time to define the domain where your DSL is useful, or if that domain turns out to be extremely narrow. Spreadsheets are a wonderful abstraction for some things, but you wouldn't build an OS with them, nor even a simple web app. Perhaps they can extend the abstraction until it can become 'nearly general-purpose' (after all, you wouldn't really write an OS in Java either), but I don't think that's guaranteed.
- z3t4 7y agoI know you like to write HTML. But stop doing it! So how do you define view state without HTML? You use functions! Then you can use any paradigm you like. And you get performance. Static sites and static site generators is still a thing, but it works very different from a client side app. Then we have the in-between with an app that renders a static view on the server. But you have to stop writing client side apps like if they where server rendered.
- dakom 7y agoI spent a fair amount of time dabbling with FRP - for example, wrote a Pong for the web using SodiumFRP and Purescript[0] imho FRP is absolutely elegant and wonderful when it all comes together. The difficulty, I found, is iterating and hacking away in order to discover what the end result was meant to be all along. In that respect FRP does slow down development time (at least in my hands. Maybe those with more expertise could iterate faster). I'd imagine that even in that scenario it could be fruitful to use something less robust for prototyping, and then implement it with FRP for a maintainable release version that's easier to reason about. [0] https://github.com/dakom/frpong https://github.com/dakom/frpong
- iamwil 7y agoWhat did you find that you had to hack away? Was it notions of how to do things from your previous experience as a programmer? Or was it more specific to the domain problem at hand? If it's the latter, then I'd argue that's part of the exploration of the problem you're trying to solve, no?
- dakom 7y agoHmmm good question! I can't say for sure - I guess it was a bit of both. In either case, I found it's faster to play around with changes in other approaches, though another way of phrasing that could be that it's easier to break things too :)
- m4r35n357 7y agoEven the article doesn't explain what FRP is . . .