Hacker News new | past | comments | ask | show | jobs | submit login
Spreadsheet-like programming in Haskell (haskellforall.com)
148 points by lelf on June 14, 2014 | hide | past | favorite | 47 comments



The article claims to be about the power of Applicative (and/or spreadsheets?), but I've been writing Haskell for about a year and am comfortable with all of the canonical Haskell abstractions including `Applicative`, and this made basically zero sense to me. Beyond familiarity with Applicative, the author also assumes the reader has facility with Controller, Fold, Managed, View, the Pipes library, Lens, and a host of functions I had never seen, such as last (not the Prelude version), stdinLines, tick, and runMVC. Assuming this, he throws out the definition of Updatable on top of that like it makes perfect sense ("just a Fold sitting in front of a Managed Controller". Oh, well then.). Basically, two or three paragraphs in and I am already completely lost. I don't even know what problem it is we're trying to solve, and I have no idea what it has to do at all with spreadsheets.

This is one of the downsides of Haskell; with so much emphasis on abstraction, code often ends up being just that: so damn abstract that it's practically inscrutable except to the very few who are familiar with what's going on. I guess this article was written for an audience with very broad and detailed knowledge of some complicated Haskell libraries -- meaning it's not so important that anyone else be able to make head or tails out of what he's talking about. Which is ok, but it does add to the impression that Haskell is an exclusive club.

Also, this part sticks out as confusing: The type signature of `example` does not include IO (unless Updatable has IO on under the hood), and yet the language above suggests that it will change, i.e. that it is mutable:

> example will update every time lastLine or seconds updates, caching and reusing portions that do not update. For example, if lastLine updates then only the first field of Example will change. Similarly, if seconds updates then only the second field of Example will change.

Can someone clear this up for me?


I confess that I also do not understand the code in the article. (But I am still only a student of Haskell.) I can only guess, based on my own work with this idea of Cells-type programming, that the author means the following:

Suppose you have three data nodes, or cells: A, B, C, and D. A holds the value 5, B holds 3, C is defined as A+B, and D is defined as B*C. In a spreadsheet, changing cell A will automatically update C, because C directly depends on A. It will also update D because it transitively depends on B through C, and C has changed. This library (and the Clojure one I mentioned in my other post) lets you define data structures which behave the same way.

In a pure environment, you can emulate this using only functions. In a non-pure environment, automatically updating values can be quite nice. You use this to implicitly trigger linked behaviors. In a UI, this could mean changing the state of several elements in response to some input without having to explicitly say updateElementA(), updateElementB(), and so on.


Thanks, yeah that's really helpful in getting a sense of the problem this is attempting to address. I can definitely see why it's nice to have a simple (to use) and compact API behind this. I wish that Gabriel had taken a similar approach in explaining this library (start with a description of the problem, then a high-level idea for a solution, then some specifics, etc). But regardless, I have the utmost respect for Gonzalez, and give him props for what looks like a(nother) great library.


If you want to familiarize yourself more with my `mvc` and `foldl` library, you can find the blog posts describing them here:

http://www.haskellforall.com/2014/04/model-view-controller-h...

http://www.haskellforall.com/2013/08/composable-streaming-fo...

It might seem like too much abstraction until you realize that the alternative would be the following obtuse type:

    data Updatable a = forall x y . Updatable (forall r . ((x, x -> y -> x, x -> a, STM (Maybe y)) -> IO r) -> IO r))
That's what you get if you completely expand out the implementation of `Updatable`. This is why I build up these abstractions from smaller composable pieces (i.e. `Fold` and `Managed` and `Controller`), each of which is intrinsically useful in isolation.

However, I think if you are trying to understand how `Managed` and `Controller` and `Fold` work all in one go, you're going about it the wrong way. Haskell lends itself really well to abstracting over the implementation by specifying mathematical equations inspired by category theory that the implementation obeys. This is not the fake kind of abstraction that other languages promise but never actually deliver (i.e. abstractions that leak and forces you to read source code, often times several layers deep). Rather, everything you need to know about the abstraction layer immediately underneath you is completely summarized by a succinct set of equations that you can then use to prove a new set of equations for the immediately following layer. This post gives an example of this layered proof process:

http://www.haskellforall.com/2013/12/equational-reasoning.ht...

By composing these small, correct-by-construction layers of equations you can grow to arbitrary complexity while always preserving correctness. More importantly, you never need to reason about more than a single layer at a time since you've decoupled each layer's correctness proofs from each other. Contrast this with other languages where you often have to reason simultaneously over many layers of abstractions to debug difficult issues or prove correctness.

To answer the meat of your question, all you really need to know to understand how `Updatable` works is that:

* `Fold e` is an `Applicative`, for all `e`

* `Managed (Controller e)` is a `Monoid`, for all `e`

* `onLeft` and `onRight` are `Applicative` homomorphisms (this detail is noted in the library source code but I omitted it from the blog post)

Those four properties concisely summarize everything you need to know about every abstraction underneath `Updatable`. If you approach this correctly, there is no need to dig into their source code further to understand how they work. Truthfully, I would love if you were to dig into their source code to learn how they work, but if you really want to level up as a programmer then you need to start thinking more abstractly, layer-by-layer, instead of trying to fit the entire programming stack into your head all at once.


Thanks, I appreciate the further explanation. However, I take issue with you telling me "if you really want to level up as a programmer then you need to start thinking more abstractly." I don't think it's very appropriate to tell someone what they need to do to "level up" as a programmer, when you have no idea of their abilities as a programmer (and even if you do, it comes off as arrogant). Perhaps a better way to phrase it would be "I've found that thinking more abstractly really lets one level up as a programmer"?


My mistake. My intention was to get you excited about equational reasoning, not talk down to you. I apologize.


No problem. Thanks for the apology. I will take the opportunity to learn more about equational reasoning in Haskell. I'm currently going through TAPL and Software Foundations, so my theoretical focus in Haskell is more on type theory and less on category theory, although that's long been on my "to-learn" list. If that makes sense :)


That makes total sense. Also, type theory is a very fascinating research area, too, especially with the advent of homotopy type theory and practical implementations of dependent types like Idris.


I know a few of the investment banks have this kind of thing internally, implemented as a DAG: http://en.wikipedia.org/wiki/Directed_acyclic_graph. Cool stuff.


Many reactive dataflow programs are DAG based (at least most major 3D/CGI packages are). Simple and powerful.


My reactive programming language can handle cyclic dependencies; DAGs are too inexpressive for general use (e.g. iterative computations). Getting that to work correctly is kind of scary though (especially when non-monotonic change is also supported).


What language would that be? I have skimmed through your papers, and they seem interesting, but can't find any downloads to play with :-)


Yinyang still. I want to release something soon, but need to find a purpose for it; right now it's just fly by night language design. I was also thinking about porting the editor to mono.cairo so more than just win users could play with it (going to javascript is a no go given no multithreading with shared memory).


I guess "working correctly" for cyclic dependencies means you need to introduce the concept of time and be careful to update everything in the proper moment? What is this useful for?


See http://research.microsoft.com/apps/pubs/default.aspx?id=2112... if you haven't already. I have both time and phases; time is used for versions and discrete updated via event handling; phases are used to ensure state doesn't get "stuck" in a cycle on a non-monotonic change. Rollback is used instead of carefully updating anything in the right order, phases however suppress when updates can be seen during processing.

It's generally useful for writing reactive, incremental, iterative programs.


I wrote something similar for Clojure: https://github.com/gcv/dgraph


I don't know enough Haskell to really know what the article is talking about, but to my very untrained eye, the idea also seems a little like this Clojure library: https://github.com/tailrecursion/javelin


Whenever I have tried spinning up a GUI on Haskell, I have always met with disaster. I think only a native (not Virtual Machine) Linux installation is the only hope, and that still is tricky.

Frustrating.



I have not had a problem on nixos on my VMware fusion box, or the same set up on my desktop. Nixos has nearly atomic package management so it is easy to set and deconstruct environment or try multiple solutions out in parallel in different profiles.


Looking at the example video provided I feel like I must be missing something; it doesn't really resemble a spreadsheet to me.


Yep. That's something I see a lot when looking at stuff from the FP community: map a commonly used term onto something that is easy to do with FP, losing almost all relevant properties. Then claim how the ease of doing <commonly used term> in FP shows the superiority of the FP approach.


Do you have any examples I can look at?


Is it the limited number of cells that makes it not resemble a spreadsheet or another feature?


The limited number of cells, the use of up/down increments to change values instead of typing, the lack of row/column coordinate system, the lack of any kind of an apparent way to operate on multiple cells at once, the fact that the cells don't actually look like cells... it's a lot easier to come up with ways it doesn't resemble a spreadsheet than ways that it does.


Sure it is a proof of concept and is about the spreadsheet computational model not making a full fledged spreadsheet application like Microsoft excel.

I thought you meant you saw some significant barriers to a full implementation or something fundamentally different in the underlying model that was not spreadsheet like.


I have two takeaways from this - first is that spreadsheets are an accessible metaphor, and grok'able by many for whom coding as we know it is too long and hard to learn.

So on the surface I think the superficial thrust of this is rather blunted.

But, and it's a really big but, software is the new literacy. And it is long and hard to learn to read and write, but we force our children to do it as a society because of the orders of magnitude benefits.

And so the same will become true of software - but not at the paltry expressive level of say, pg's Blub language - but at something Haskell is trying for.

I say there are three kinds of stages of sophistication for a person or a company - not coding, automating and compiler.

We want our children to be operating at the compiler level - so we want them to be using the languages Haskell will evolve into.

Now where did I put my copy of SICP?

Edit: Blub language not Blah...


I am eager to learn a new paradigm, haskell look interesting but reading the post make me thing that a great language needs someone great at explaining the core concepts, ideas and problems. Haskell for all seems to be a contradictions because to be understood by all is expensive in time and effort. Hope to learn more about haskell.


Learning Haskell is a deep rabbit hole. Make sure you decide when it is enough, there's tons to learn and you can't be an expert on everything and you don't have to programming in Haskell.


I am experimenting with something similar for a java web framework https://github.com/constructo/chemflow . Its kind of sketchy right now but achieves the spreadsheet-like programming nicely.


To ellaborate a bit further, I don't know haskell but I can agree that the authors code doesn't look like spreadsheet programming.

My approach is inspired by join calculus which is centered on the concept of waiting on a set of signals/cells to trigger a reaction (I ignore the concurrency capabilities of join calculus which make it a bit more complex). It seems to me that FRP takes the long route to achieve this since its focused on event handling.

Anyhow, this can be easily achieved with a simplified cactus stack where each stack "frame" holds a reference to its parent so that it notifies its parent when its value is set, then when all of the stack frames are ready the procedure associated to it is triggered.

This type of stack has some interesting capabilities including memory friendly infinite recursion and compound-key data structures. I believe that it has potential for artificial intelligence and the development of modern dataflow languages.


Web App builder: Turning the idea upside down, this helps smart non programmers create software with a spreadsheet. www.cellmaster.com.au (I only have a few early adopters).


A really great example of why Haskell will be forever relegated to academic circles.


Your prediction is already false. It's extra-silly coming in the same week that Facebook open-sourced a piece of their own infrastructure written in Haskell.

And I'm sure the high frequency traders using it would chuckle to hear that they are "academics".


Why do you say that? Your comment seems to be entirely negative, and you seem to have seen something that I haven't. Please can you expand on it?

In particular, the cynical part of my mind wonders if it's simply because you can't read the code, and because of that haven't really bothered to follow the argument. I'm sure you must have deeper reasons that that, and I, for one, would appreciate an explanation of your reasoning.


As a newcomer to Haskell may I offer an explanation: the article is full of jargon and thus hard to follow.


Yes, it assumes some knowledge of the language. But imagine if every article about, say, Ruby, had to explain things in a way that someone who'd only ever seen C would understand? Authors would be hamstrung, unable to talk about things at any level other than the most elementary.

If you're going to talk about the power of a language you have to allow the use of language that talks about that power. To talk about what you can do in Haskell beyond toy problems you need to allow people to use more than just toy language.

If readers aren't willing to do any work, its tough to help them learn anything new.


It doesn't just assume knowledge of the language though. Assuming knowledge of Applicative, Monad and Functor is fine but as the current top comment says there is a lot more than that. Most of which you wouldn't find in a normal Haskell tutorial/article


No, exactly. This is not a beginner tutorial - there are plenty of those. This is for people who have already acquired some knowledge of the language. It's an intermediate article for those looking to move beyond the toy programs solving toy problems usually presented.


Author here: the concept of `Applicative`s is unique to Haskell and has no parallel in other programming languages. This makes the post difficult to write to a broad audience. Instead, I just tried to show the neat things you could do with `Applicative`s to try to entice people to learn more about them.


I respectfully suggest that Applicative is not what makes this article hard to understand. I agree with thinkpad20 here: https://news.ycombinator.com/item?id=7894258


I don't think it's unique to Haskell. The Scalaz library for Scala also provides Applicative:

https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/...

Do they differ in some drastic way? (Note: I'm not super familiar with the Haskell version.)


Oh, I wasn't aware Scalaz had applicative. Then I stand corrected.


That's definitely a valid criticism of the article, but not really an explanation for the OP's post AFAICT.


I don't think a beginner would be in a position to judge what is 'jargon' and what is essential terminology.


...Haskell will be forever relegated to academic circles.

http://c2.com/cgi/wiki?BlubParadox


There's a difference between "academic" and "clever".




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: