The Good, the Bad and the GUI

Dear All, Haskell is great for great many areas, let me name just two: - parsers, translators, interpreters, compilers; highly concurrent systems. Haskell is however not great for GUIs. I've been thinking a little why this is so. I think one of the reasons might be that in Haskell it is unusual to deal with data that is incomplete or otherwise erroneous. Let me try to explain, what I mean, by example. If you declare Person class in Java, you automatically get a thingy that you can readily use in UI construction, because all the fields can temporarily be null, even the required ones. In Haskell you'd need two data types: the usual proper Haskell data type, and another which wraps every field in Maybe, facilitates editing, validation, etc. Perhaps it would be possible to generate one data type from the other, or generate both from a common specification. Let me write the same thing in other words. It is not controversial to say on this list that specifying what is correct means, is a good idea. But for GUIs, in addition to the strong type, you need another relaxed type to hold the values temporarily, until the human manages to deliver correct data, often by trial and error. Comments welcome. -- Kind regards, Wojtek Narczyński

On Mon, Aug 11, 2014 at 6:16 PM, Wojtek Narczyński
Let me write the same thing in other words. It is not controversial to say on this list that specifying what is correct means, is a good idea. But for GUIs, in addition to the strong type, you need another relaxed type to hold the values temporarily, until the human manages to deliver correct data, often by trial and error.
I think there are far larger issues to deal with first: you need to have a sensible connection from Haskell to a GUI before you can worry about getting data across it. At the moment, we have either mostly procedural interfaces to common procedural toolkits (WxHaskell, gtk2hs) or a number of still largely experimental FRP interfaces. It is not particularly difficult to deal with the step that you highlight once we have solved the basic interface to the GUI; you can do it with Template Haskell, or generics, or lens, or with semi-typed interfaces between Haskell and the GUI (for example, I can see Aeson sitting in this layer). But figuring out how to work it in depends on knowing what we're working it into. -- brandon s allbery kf8nh sine nomine associates allbery.b@gmail.com ballbery@sinenomine.net unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net

I think that the GUI people hace to embrace the formlet concept, used in
HTML interfaces sooner better than later. The GUI development has lost the
train by trying to interface C libraries that are decades old. The reactive
solutions complicates the problem rather than to simplify it. That means
that they are not the correct paradigm.
2014-08-12 0:25 GMT+02:00 Brandon Allbery
On Mon, Aug 11, 2014 at 6:16 PM, Wojtek Narczyński
wrote: Let me write the same thing in other words. It is not controversial to say on this list that specifying what is correct means, is a good idea. But for GUIs, in addition to the strong type, you need another relaxed type to hold the values temporarily, until the human manages to deliver correct data, often by trial and error.
I think there are far larger issues to deal with first: you need to have a sensible connection from Haskell to a GUI before you can worry about getting data across it. At the moment, we have either mostly procedural interfaces to common procedural toolkits (WxHaskell, gtk2hs) or a number of still largely experimental FRP interfaces.
It is not particularly difficult to deal with the step that you highlight once we have solved the basic interface to the GUI; you can do it with Template Haskell, or generics, or lens, or with semi-typed interfaces between Haskell and the GUI (for example, I can see Aeson sitting in this layer). But figuring out how to work it in depends on knowing what we're working it into.
-- brandon s allbery kf8nh sine nomine associates allbery.b@gmail.com ballbery@sinenomine.net unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
-- Alberto.

On 12.08.2014 00:53, Alberto G. Corona wrote:
I think that the GUI people hace to embrace the formlet concept, used in HTML interfaces sooner better than later. The GUI development has lost the train by trying to interface C libraries that are decades old. The reactive solutions complicates the problem rather than to simplify it. That means that they are not the correct paradigm.
I'm mainly interested in HTML/JS GUIs. Perhaps I should have stated it explicitly upfront.

Wojtek. What you say is exactly what has been solved time ago by fomlets in
Web interfaces. There are many formlet library and almost all haskell web
framework use formlets.
2014-08-12 0:57 GMT+02:00 Wojtek Narczyński
On 12.08.2014 00:53, Alberto G. Corona wrote:
I think that the GUI people hace to embrace the formlet concept, used in HTML interfaces sooner better than later. The GUI development has lost the train by trying to interface C libraries that are decades old. The reactive solutions complicates the problem rather than to simplify it. That means that they are not the correct paradigm.
I'm mainly interested in HTML/JS GUIs. Perhaps I should have stated it explicitly upfront.
-- Alberto.

But formlets are implemented in the server side. and you probably think in
applications with heavy use of JavaScript for validations, interaction
etc. In this case, there is a formlet implementation in the client side,
which is my.. Ahem!... package hplaygroud:
https://github.com/agocorona/hplayground
2014-08-12 1:14 GMT+02:00 Alberto G. Corona
Wojtek. What you say is exactly what has been solved time ago by fomlets in Web interfaces. There are many formlet library and almost all haskell web framework use formlets.
2014-08-12 0:57 GMT+02:00 Wojtek Narczyński
: On 12.08.2014 00:53, Alberto G. Corona wrote:
I think that the GUI people hace to embrace the formlet concept, used in HTML interfaces sooner better than later. The GUI development has lost the train by trying to interface C libraries that are decades old. The reactive solutions complicates the problem rather than to simplify it. That means that they are not the correct paradigm.
I'm mainly interested in HTML/JS GUIs. Perhaps I should have stated it explicitly upfront.
-- Alberto.
-- Alberto.

W dniu 2014-08-12 01:22, Alberto G. Corona pisze:
But formlets are implemented in the server side. and you probably think in applications with heavy use of JavaScript for validations, interaction etc. In this case, there is a formlet implementation in the client side, which is my.. Ahem!... package hplaygroud:
Very interesting, please allow a few questions about your approach: 1. Would it be possible to save a snapshot of a paritally filled form on the server? 2. Would it be possible to display the sum before the values: 3 = [ 1] + [ 2] <-- this is rendered HTML, not Haskell? (I thought I would have more questions, but somehow I can't think of any right now...) -- Kind regards, Wojtek

2014-08-12 21:18 GMT+02:00 Wojciech Narczyński
W dniu 2014-08-12 01:22, Alberto G. Corona pisze:
But formlets are implemented in the server side. and you probably think in applications with heavy use of JavaScript for validations, interaction etc. In this case, there is a formlet implementation in the client side, which is my.. Ahem!... package hplaygroud:
https://github.com/agocorona/hplayground
Very interesting, please allow a few questions about your approach:
1. Would it be possible to save a snapshot of a paritally filled form on the server?
hplayground is client side. but by means of Haste.Ajax it is possible to send something to a server. do r <- (+) <$> inputAndSend <*> inputAndSend p (show r) ++> noWidget where inputAndSend= do r <- inputInt Nothing `wake` OnKeyPress <++ br sendInt r return r sendInt i= send the int trough Haste.Ajax 2. Would it be possible to display the sum before the values: 3 = [ 1] + [
2] <-- this is rendered HTML, not Haskell?
yes, using "at":
do wraw $ div ! id "result" $ noHtml r <- (+) <$> inputInt Nothing `wake` OnKeyPress <++ br <*> inputInt Nothing `wake` OnKeyPress <++ br at "result" Html $ p (show r) ++> noWidget
(I thought I would have more questions, but somehow I can't think of any right now...)
-- Kind regards, Wojtek
-- Alberto.

sorry: instead of
at "result" Html $ ....
is
at "result" Insert $ ....
2014-08-12 21:59 GMT+02:00 Alberto G. Corona
2014-08-12 21:18 GMT+02:00 Wojciech Narczyński
: W dniu 2014-08-12 01:22, Alberto G. Corona pisze:
But formlets are implemented in the server side. and you probably think in applications with heavy use of JavaScript for validations, interaction etc. In this case, there is a formlet implementation in the client side, which is my.. Ahem!... package hplaygroud:
https://github.com/agocorona/hplayground
Very interesting, please allow a few questions about your approach:
1. Would it be possible to save a snapshot of a paritally filled form on the server?
hplayground is client side. but by means of Haste.Ajax it is possible to send something to a server.
do r <- (+) <$> inputAndSend <*> inputAndSend p (show r) ++> noWidget where inputAndSend= do r <- inputInt Nothing `wake` OnKeyPress <++ br sendInt r return r sendInt i= send the int trough Haste.Ajax
2. Would it be possible to display the sum before the values: 3 = [ 1] +
[ 2] <-- this is rendered HTML, not Haskell?
yes, using "at":
do wraw $ div ! id "result" $ noHtml r <- (+) <$> inputInt Nothing `wake` OnKeyPress <++ br <*> inputInt Nothing `wake` OnKeyPress <++ br
at "result" Html $ p (show r) ++> noWidget
(I thought I would have more questions, but somehow I can't think of any right now...)
-- Kind regards, Wojtek
-- Alberto.
-- Alberto.

Well, it is not a hack. It is the way hplayground works . normally it
rewrite the HTML DOM of the implicit divs that are below the event source.
"at" permits to assign freely that location.
2014-08-12 22:51 GMT+02:00 Wojtek Narczyński
On 12.08.2014 22:01, Alberto G. Corona wrote:
sorry: instead of
at "result" Html $ ....
is
at "result" Insert $ ....
Oh, so basically, you create an element and later on replace it with the right content. I think it's a hack, but a neat one.
-- Wojtek
-- Alberto.

On 12.08.2014 23:27, Alberto G. Corona wrote:
Well, it is not a hack. It is the way hplayground works . normally it rewrite the HTML DOM of the implicit divs that are below the event source. "at" permits to assign freely that location.
Okay, I see. 3. Are you yourself aware of any serious limitations of your approach? -- Wojtek

I did the todo application, (see todomvc.com) to check if the concept was
expressive and robust enough to do it:
https://github.com/agocorona/hplay-todo
I think that the model works and the haste compiler works very well too. I
don´t know any serious limitation. "wcallback" generates spurious DOM
elements and so on, but that can be fixed.
2014-08-12 23:42 GMT+02:00 Wojtek Narczyński
On 12.08.2014 23:27, Alberto G. Corona wrote:
Well, it is not a hack. It is the way hplayground works . normally it rewrite the HTML DOM of the implicit divs that are below the event source. "at" permits to assign freely that location.
Okay, I see.
3. Are you yourself aware of any serious limitations of your approach?
-- Wojtek
-- Alberto.

On 13.08.2014 00:13, Alberto G. Corona wrote:
I did the todo application, (see todomvc.com http://todomvc.com) to check if the concept was expressive and robust enough to do it:
I have seen the app running, I'm yet to take a look at the code.
I think that the model works and the haste compiler works very well too. I don´t know any serious limitation. "wcallback" generates spurious DOM elements and so on, but that can be fixed.
Great. Overall, I'm impressed. This really looks like a practical way to keep the JS mess under the carpet.

Maybe you should port hplayground to purescript and virtual-dom :-) On Wednesday, 13 August 2014 00:13:42 UTC+2, Alberto G. Corona wrote:
I did the todo application, (see todomvc.com) to check if the concept was expressive and robust enough to do it:
https://github.com/agocorona/hplay-todo
I think that the model works and the haste compiler works very well too. I don´t know any serious limitation. "wcallback" generates spurious DOM elements and so on, but that can be fixed.
2014-08-12 23:42 GMT+02:00 Wojtek Narczyński
javascript:>: On 12.08.2014 23:27, Alberto G. Corona wrote:
Well, it is not a hack. It is the way hplayground works . normally it rewrite the HTML DOM of the implicit divs that are below the event source. "at" permits to assign freely that location.
Okay, I see.
3. Are you yourself aware of any serious limitations of your approach?
-- Wojtek
-- Alberto.

2014-08-13 11:05 GMT+02:00 Rik van der Kleij
Maybe you should port hplayground to purescript and virtual-dom :-)
why? for some special reason?
On Wednesday, 13 August 2014 00:13:42 UTC+2, Alberto G. Corona wrote:
I did the todo application, (see todomvc.com) to check if the concept was expressive and robust enough to do it:
https://github.com/agocorona/hplay-todo
I think that the model works and the haste compiler works very well too. I don´t know any serious limitation. "wcallback" generates spurious DOM elements and so on, but that can be fixed.
2014-08-12 23:42 GMT+02:00 Wojtek Narczyński
: On 12.08.2014 23:27, Alberto G. Corona wrote:
Well, it is not a hack. It is the way hplayground works . normally it rewrite the HTML DOM of the implicit divs that are below the event source. "at" permits to assign freely that location.
Okay, I see.
3. Are you yourself aware of any serious limitations of your approach?
-- Wojtek
-- Alberto.
-- Alberto.

Because it looks like virtual-dom is very well suited for how hplayground works. It's very efficient in rerendering the DOM tree when you have local changes. It's also very fast, see http://elm-lang.org/blog/Blazing-Fast-Html.elm Purescipt because it has a lot of speed in development (libraries) and generates in general leaner javascript. But I have no particular objections against Haste :-) On Wednesday, 13 August 2014 11:55:04 UTC+2, Alberto G. Corona wrote:
2014-08-13 11:05 GMT+02:00 Rik van der Kleij
javascript:>: Maybe you should port hplayground to purescript and virtual-dom :-)
why? for some special reason?
On Wednesday, 13 August 2014 00:13:42 UTC+2, Alberto G. Corona wrote:
I did the todo application, (see todomvc.com) to check if the concept was expressive and robust enough to do it:
https://github.com/agocorona/hplay-todo
I think that the model works and the haste compiler works very well too. I don´t know any serious limitation. "wcallback" generates spurious DOM elements and so on, but that can be fixed.
2014-08-12 23:42 GMT+02:00 Wojtek Narczyński
: On 12.08.2014 23:27, Alberto G. Corona wrote:
Well, it is not a hack. It is the way hplayground works . normally it rewrite the HTML DOM of the implicit divs that are below the event source. "at" permits to assign freely that location.
Okay, I see.
3. Are you yourself aware of any serious limitations of your approach?
-- Wojtek
-- Alberto.
-- Alberto.

Yep, but virtual-dom is more appropriate for declarative reactive
frameworks like elm. It need to know what parts of the DOM must be
refreshed because the whole elm expression is reevaluated when an event
happens. It need to detect the changes. Otherwise, it would have to repaint
the whole screen in each event.
Declarative reactive is like a giant event handler that all the events
execute. It may have some event/signal preprocessing to mix events/signals
depending on timings by means of some special combinators, but at the end
it executes the whole declarative expression, which includes the
re-generation of all the rendering.
hplayground execute just the part of the monad corresponding to the branch
in which the event happened. So it does not need to maintain the old and
the new version of the DOM in order to detect the parts to be updated. It
updates the affected branch of the DOM directly. So it must be faster (I
did not check it however).
2014-08-13 12:34 GMT+02:00 Rik van der Kleij
Because it looks like virtual-dom is very well suited for how hplayground works. It's very efficient in rerendering the DOM tree when you have local changes. It's also very fast, see http://elm-lang.org/blog/Blazing-Fast-Html.elm
Purescipt because it has a lot of speed in development (libraries) and generates in general leaner javascript. But I have no particular objections against Haste :-)
On Wednesday, 13 August 2014 11:55:04 UTC+2, Alberto G. Corona wrote:
2014-08-13 11:05 GMT+02:00 Rik van der Kleij
: Maybe you should port hplayground to purescript and virtual-dom :-)
why? for some special reason?
On Wednesday, 13 August 2014 00:13:42 UTC+2, Alberto G. Corona wrote:
I did the todo application, (see todomvc.com) to check if the concept was expressive and robust enough to do it:
https://github.com/agocorona/hplay-todo
I think that the model works and the haste compiler works very well too. I don´t know any serious limitation. "wcallback" generates spurious DOM elements and so on, but that can be fixed.
2014-08-12 23:42 GMT+02:00 Wojtek Narczyński
: On 12.08.2014 23:27, Alberto G. Corona wrote:
Well, it is not a hack. It is the way hplayground works . normally it rewrite the HTML DOM of the implicit divs that are below the event source. "at" permits to assign freely that location.
Okay, I see.
3. Are you yourself aware of any serious limitations of your approach?
-- Wojtek
-- Alberto.
-- Alberto.
-- Alberto.

On 12.08.2014 01:14, Alberto G. Corona wrote:
Wojtek. What you say is exactly what has been solved time ago by fomlets in Web interfaces. There are many formlet library and almost all haskell web framework use formlets.
AFAIK, formlets at the server are very much like PHP, only with neater syntax, strong typing, and the like. Formlets tutorials teach you to put all your validation into the GUI, you really can't do much worse. But, Alberto, your client side formlets look very interesting. I printed your Monad.Reader paper, and I'm definitely going to explore your ideas. -- Kind regards, Wojtek Narczyński

2014-08-12 10:31 GMT+02:00 Wojtek Narczyński
On 12.08.2014 01:14, Alberto G. Corona wrote:
Wojtek. What you say is exactly what has been solved time ago by fomlets in Web interfaces. There are many formlet library and almost all haskell web framework use formlets.
AFAIK, formlets at the server are very much like PHP, only with neater syntax, strong typing, and the like. Formlets tutorials teach you to put all your validation into the GUI, you really can't do much worse.
I think that this horizontal separating the GUI from his application logic is a wrong conception of separation of concern.. as strange as it may sound, since that makes applications and components non composable. The MVC model is non composable! A better separation of concern, for many purposes, is the vertical one in which each functionality include its own interface, logic and data model. The obstacle for implementing this kind of separation of concern is mainly technological, because each of the three layes uses different languages, so an horizontal separation is easier. But it is not appropriate for most purposes. It is very bad for creating GUIs!! http://haskell-web.blogspot.com.es/2014/05/separation-of-concerns-by-problem...
But, Alberto, your client side formlets look very interesting. I printed your Monad.Reader paper, and I'm definitely going to explore your ideas.
Thanks!
-- Kind regards, Wojtek Narczyński
-- Alberto.

For the original question: take a look at functional reactive programming (FRP). It takes a slightly different approach to the whole GUI problem, but, I've found, obviates some of your issues. You can quickly play around with FRP and HTML UIs by using threepenny-gui and Reactive Banana. The former is a simple UI framework that lets you create and interact with HTML in Haskell, and the latter in a nice library for FRP. They work well together: http://apfelmus.nfshost.com/blog/2013/08/02-reactive-banana-threepenny.html There's a nice tutorial about FRP and Reactive Banana you can read on the Haskell Wiki. I haven't had the chance to go through it myself, but it looks promising. http://www.haskell.org/haskellwiki/FRP_explanation_using_reactive-banana If you're wondering about Haskell and UIs, I think FRP is the best place to look—it provides the most pleasant semantics for programming UIs that I've come across, although most of the libraries are still a bit experimental. (Implementing the exact semantics we'd like turned out to be very difficult!)
The reactive solutions complicates the problem rather than to simplify it. That means that they are not the correct paradigm.
That's a very hasty, superficial way to dismiss a whole paradigm!
FRP libraries have proven *difficult to implement*, but this does not mean
they somehow "complicate the problem". The real insight with FRP is
developing a nice semantics *for the end user* and making it simpler to
work with the libraries, at the expense of a more complex implementation.
It's a parallel to functional programming at large: we're willing to trade
complexity in GHC in return for a nicer high-level programming environment.
Formlets are an interesting concept, but they seem to be significantly more
narrow than FRP. How do formlets address continuous things like animations
or mouse movement?
Also, a lot of the examples (at least on the Haskell wiki[1]) seem pretty
amenable to FRP. How is
chooseBool :: Form Bool
chooseBool = enumRadio [(True, "Yes"), (False, "No")] True
significantly different from just providing a Behavior Bool in the spirit
of FRP?
On Mon, Aug 11, 2014 at 3:57 PM, Wojtek Narczyński
On 12.08.2014 00:53, Alberto G. Corona wrote:
I think that the GUI people hace to embrace the formlet concept, used in HTML interfaces sooner better than later. The GUI development has lost the train by trying to interface C libraries that are decades old. The reactive solutions complicates the problem rather than to simplify it. That means that they are not the correct paradigm.
I'm mainly interested in HTML/JS GUIs. Perhaps I should have stated it explicitly upfront.
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

2014-08-12 1:21 GMT+02:00 Tikhon Jelvis
For the original question: take a look at functional reactive programming (FRP). It takes a slightly different approach to the whole GUI problem, but, I've found, obviates some of your issues.
You can quickly play around with FRP and HTML UIs by using threepenny-gui and Reactive Banana. The former is a simple UI framework that lets you create and interact with HTML in Haskell, and the latter in a nice library for FRP. They work well together:
http://apfelmus.nfshost.com/blog/2013/08/02-reactive-banana-threepenny.html
There's a nice tutorial about FRP and Reactive Banana you can read on the Haskell Wiki. I haven't had the chance to go through it myself, but it looks promising.
http://www.haskell.org/haskellwiki/FRP_explanation_using_reactive-banana
If you're wondering about Haskell and UIs, I think FRP is the best place to look—it provides the most pleasant semantics for programming UIs that I've come across, although most of the libraries are still a bit experimental. (Implementing the exact semantics we'd like turned out to be very difficult!)
The reactive solutions complicates the problem rather than to simplify it. That means that they are not the correct paradigm.
That's a very hasty, superficial way to dismiss a whole paradigm!
Yes! I was just trying to be a bit provoking. Sorry. The objections about the use of current FRP models for GUIs are here: http://homepages.cwi.nl/~ploeg/papers/monfrp.pdf and here: https://www.fpcomplete.com/user/agocorona/a-monad-for-reactive-programming-p... Allthough FRP is too wide. Monadic FRP is more appropriate for GUIs for the same reasons. hplayground uses monadic FRP + formlets
FRP libraries have proven *difficult to implement*, but this does not mean they somehow "complicate the problem". The real insight with FRP is developing a nice semantics *for the end user* and making it simpler to work with the libraries, at the expense of a more complex implementation. It's a parallel to functional programming at large: we're willing to trade complexity in GHC in return for a nicer high-level programming environment.
Formlets are an interesting concept, but they seem to be significantly more narrow than FRP. How do formlets address continuous things like animations or mouse movement?
Also, a lot of the examples (at least on the Haskell wiki[1]) seem pretty amenable to FRP. How is
chooseBool :: Form Bool chooseBool = enumRadio [(True, "Yes"), (False, "No")] True
significantly different from just providing a Behavior Bool in the spirit of FRP?
On Mon, Aug 11, 2014 at 3:57 PM, Wojtek Narczyński
wrote: On 12.08.2014 00:53, Alberto G. Corona wrote:
I think that the GUI people hace to embrace the formlet concept, used in HTML interfaces sooner better than later. The GUI development has lost the train by trying to interface C libraries that are decades old. The reactive solutions complicates the problem rather than to simplify it. That means that they are not the correct paradigm.
I'm mainly interested in HTML/JS GUIs. Perhaps I should have stated it explicitly upfront.
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
-- Alberto.

On 12.08.2014 11:40, Alberto G. Corona wrote:
> The reactive solutions complicates the problem rather than to simplify it. That means that they are not the correct paradigm.
That's a very hasty, superficial way to dismiss a whole paradigm!
Yes!
I was just trying to be a bit provoking. Sorry.
I would really like to see a complex web form (think Facebook, VAT Invoice, Tax forms) done in FRP. The harsh reality is that FRP for GUIs still has to prove that its utility reaches beyond the game of Pong. -- Wojtek

Wojtek Narczyński wrote:
I would really like to see a complex web form (think Facebook, VAT Invoice, Tax forms) done in FRP. The harsh reality is that FRP for GUIs still has to prove that its utility reaches beyond the game of Pong.
Like this? http://www.haskell.org/haskellwiki/Reactive-banana/Examples#crud It's still a toy model, but I think it captures the essential difficulties. A full blown tax form would just be more of the same. Best regards, Heinrich Apfelmus -- http://apfelmus.nfshost.com

On 12.08.2014 23:50, Heinrich Apfelmus wrote:
Wojtek Narczyński wrote:
I would really like to see a complex web form (think Facebook, VAT Invoice, Tax forms) done in FRP. The harsh reality is that FRP for GUIs still has to prove that its utility reaches beyond the game of Pong.
Like this?
http://www.haskell.org/haskellwiki/Reactive-banana/Examples#crud
It's still a toy model, but I think it captures the essential difficulties. A full blown tax form would just be more of the same.
Is it live anywhere? I'd like to test it for HTML injection. The #1 difficulty is validation. Is there any in this example? I can't see any. This really does not qualify as a complex web form. You'll get _exponentially_ more of the same. See paper "Plato: A Compiler for Interactive Web Forms", http://www.cs.uic.edu/~hinrichs/papers/hinrichs2011plato.pdf -- Wojtek

Wojtek Narczyński wrote:
Heinrich Apfelmus wrote:
Wojtek Narczyński wrote:
I would really like to see a complex web form (think Facebook, VAT Invoice, Tax forms) done in FRP. The harsh reality is that FRP for GUIs still has to prove that its utility reaches beyond the game of Pong.
Like this?
http://www.haskell.org/haskellwiki/Reactive-banana/Examples#crud
It's still a toy model, but I think it captures the essential difficulties. A full blown tax form would just be more of the same.
Is it live anywhere? I'd like to test it for HTML injection.
It's actually a wxHaskell applications, the screenshot is from a temporary but now deprecated adaption to Threepenny-gui. So, the issue of HTML injection does not arise. (It would not arise in a HTML context either, because of strong typing.) The key point about this CRUD example, which is not shown in the screenshot, is that it has immediate feedback: values in the list box change as you type. Editing the name on the right-hand side will change the name in the list box, and changing the filter will immediately update the available names in the list box.
The #1 difficulty is validation. Is there any in this example? I can't see any. This really does not qualify as a complex web form.
You'll get _exponentially_ more of the same. See paper "Plato: A Compiler for Interactive Web Forms", http://www.cs.uic.edu/~hinrichs/papers/hinrichs2011plato.pdf
Validation is mainly a question of *how* to present feedback about invalid data to the user -- for instance by making invalid data impossible to enter, or by showing errors in red and retaining the last correct value, etc. I would consider this as a narrow part of GUI programming. For me, GUI programming is about user interfaces and interaction design in general, including zoom, animation, games, and so on. FRP is a better tool at this than the traditional event-based style. Of course, in the context of form validation, FRP would be a building block: It does not give any advice on which feedback to present to the user, but it does allow you to quickly implement whatever feedback you have chosen to present. Still, even for the more narrow problem of forms and input validation, I don't see how you arrive at your claim that "Haskell is however not great for GUIs". This seems like a problem that can be solved with a traditional DSL approach, and I would be surprised if Haskell were unsuitable as a host language, contrary to what your claim seems to imply. Whether DSLs along these lines are already available is another question. Alberto mentioned one, another one would be [1]. [1]: http://www.sandr.dds.nl/publications/FForms.pdf Best regards, Heinrich Apfelmus -- http://apfelmus.nfshost.com

On 13.08.2014 15:42, Heinrich Apfelmus wrote:
Validation is mainly a question of *how* to present feedback about invalid data to the user -- for instance by making invalid data impossible to enter, or by showing errors in red and retaining the last correct value, etc.
I don't even know how to capture validation rules in such a way that they were easy to use from the GUI layer. I suspect if they were captured well, whatever well might mean in this context, a functioning GUI could be autogenerated from those rules. And I don't understand FRP code. I could however understand Eduardo's client side formlets almost immediately. Not now they work below, how to use them.
Still, even for the more narrow problem of forms and input validation, I don't see how you arrive at your claim that "Haskell is however not great for GUIs". This seems like a problem that can be solved with a traditional DSL approach, and I would be surprised if Haskell were unsuitable as a host language, contrary to what your claim seems to imply. Whether DSLs along these lines are already available is another question. Alberto mentioned one, another one would be [1].
Oh, please. Haskell is great for parsing, because you can build a parser with e.g. parsec, attoparsec, uuparse, trifeca, in no time. Even I can do it. Haskell is great for concurrency, because it has lightweight threads, STM, and a fabulous book about it. Haskell is great for GUIs, because.... how about you finish this statement, I don't know how to. -- Kind reagrds, Wojtek Narczynski

Oh, please. Haskell is great for parsing, because you can build a parser with e.g. parsec, attoparsec, uuparse, trifeca, in no time. Even I can do it. Haskell is great for concurrency, because it has lightweight threads, STM, and a fabulous book about it. Haskell is great for GUIs, because.... how about you finish this statement, I don't know how to.
Before parsec, attoparsec, uuparse, et al were invented, was Haskell no good for parsing? When we speak of Haskell do we speak of the entire ecosystem, or just the language itself? I think Heinrich meant that Haskell, the language, is probably capable of carrying a great library for expressing GUI's, even if we haven't yet seen it implemented. Alex On 2014-08-13, at 5:19 PM, Wojtek Narczyński wrote:
On 13.08.2014 15:42, Heinrich Apfelmus wrote:
Validation is mainly a question of *how* to present feedback about invalid data to the user -- for instance by making invalid data impossible to enter, or by showing errors in red and retaining the last correct value, etc.
I don't even know how to capture validation rules in such a way that they were easy to use from the GUI layer. I suspect if they were captured well, whatever well might mean in this context, a functioning GUI could be autogenerated from those rules.
And I don't understand FRP code. I could however understand Eduardo's client side formlets almost immediately. Not now they work below, how to use them.
Still, even for the more narrow problem of forms and input validation, I don't see how you arrive at your claim that "Haskell is however not great for GUIs". This seems like a problem that can be solved with a traditional DSL approach, and I would be surprised if Haskell were unsuitable as a host language, contrary to what your claim seems to imply. Whether DSLs along these lines are already available is another question. Alberto mentioned one, another one would be [1].
Oh, please. Haskell is great for parsing, because you can build a parser with e.g. parsec, attoparsec, uuparse, trifeca, in no time. Even I can do it. Haskell is great for concurrency, because it has lightweight threads, STM, and a fabulous book about it. Haskell is great for GUIs, because.... how about you finish this statement, I don't know how to.
-- Kind reagrds, Wojtek Narczynski _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On 13.08.2014 23:28, Alexander Vieth wrote:
Oh, please. Haskell is great for parsing, because you can build a parser with e.g. parsec, attoparsec, uuparse, trifeca, in no time. Even I can do it. Haskell is great for concurrency, because it has lightweight threads, STM, and a fabulous book about it. Haskell is great for GUIs, because.... how about you finish this statement, I don't know how to. Before parsec, attoparsec, uuparse, et al were invented, was Haskell no good for parsing? When we speak of Haskell do we speak of the entire ecosystem, or just the language itself?
It is clear what I meant.
I think Heinrich meant that Haskell, the language, is probably capable of carrying a great library for expressing GUI's, even if we haven't yet seen it implemented.
Haskell, the language, is great for GUIs, because... "(it) is probably capable of carrying a great library for expressing GUI's, even if we haven't yet seen it implemented." This is too much, I need to sleep it off.

On Thu, Aug 14, 2014 at 01:19:19AM +0200, Wojtek Narczyński wrote:
On 13.08.2014 23:28, Alexander Vieth wrote:
Oh, please. Haskell is great for parsing, because you can build a parser with e.g. parsec, attoparsec, uuparse, trifeca, in no time. Even I can do it. Haskell is great for concurrency, because it has lightweight threads, STM, and a fabulous book about it. Haskell is great for GUIs, because.... how about you finish this statement, I don't know how to.
Before parsec, attoparsec, uuparse, et al were invented, was Haskell no good for parsing? When we speak of Haskell do we speak of the entire ecosystem, or just the language itself?
It is clear what I meant.
I think Heinrich meant that Haskell, the language, is probably capable of carrying a great library for expressing GUI's, even if we haven't yet seen it implemented.
Haskell, the language, is great for GUIs, because... "(it) is probably capable of carrying a great library for expressing GUI's, even if we haven't yet seen it implemented." This is too much, I need to sleep it off.
Perhaps you could give an example of a language that is "great for GUIs" and a great functional snippet of GUI code in that language. Otherwise we're just discussing in the abstract which tends not to be very helpful. Tom

Wojtek Narczyński wrote:
Alexander Vieth wrote:
I think Heinrich meant that Haskell, the language, is probably capable of carrying a great library for expressing GUI's, even if we haven't yet seen it implemented.
Haskell, the language, is great for GUIs, because... "(it) is probably capable of carrying a great library for expressing GUI's, even if we haven't yet seen it implemented." This is too much, I need to sleep it off.
That's indeed what I wanted to say, Alexander. Wojtek, precise wording is important to us. We make no claim that "Haskell is great for GUIs", only that it is probably capable of carrying a great library for expressing GUIs. This distinction is important because it gives advice on how to solve the problem -- is there some inherent defect in the language and its semantics that makes it difficult, or is the problem more on of manpower? Similar for the term "GUI". Apparently, you are interested in a narrow aspect of GUI programming -- input forms and validation. Which is totally fine, but not nearly as broad as GUI programming in general. The latter benefits immensely from FRP, but FRP is orthogonal to the question of validation. Best regards, Heinrich Apfelmus -- http://apfelmus.nfshost.com

On 15.08.2014 13:27, Heinrich Apfelmus wrote:
Wojtek, precise wording is important to us. We make no claim that "Haskell is great for GUIs", only that it is probably capable of carrying a great library for expressing GUIs. This distinction is important because it gives advice on how to solve the problem -- is there some inherent defect in the language and its semantics that makes it difficult, or is the problem more on of manpower?
GUIs are hard, in any language. ----------------------------------------------------------- http://www.emarcus.org/papers/gpce2009-marcus.pdf http://www.cs.uic.edu/~hinrichs/papers/hinrichs2011plato.pdf I am looking for solutions on a Haskell list, because I think chances of finding them here are higher than elsewhere. So let me ask again, any ideas on how would you write down rules for: text field lengths or numeric field ranges, in such a library, for a start?
Similar for the term "GUI". Apparently, you are interested in a narrow aspect of GUI programming -- input forms and validation. Which is totally fine, but not nearly as broad as GUI programming in general.
You are totally right here. I should have said I meant Web UIs, mostly interactive forms. -- Wojtek

If you declare Person class in Java, you automatically get a thingy that you can readily use in UI construction, because all the fields can temporarily be null, even the required ones. In Haskell you'd need two data types: the usual proper Haskell data type, and another which wraps every field in Maybe, facilitates editing, validation, etc. Perhaps it would be possible to generate one data type from the other, or generate both from a common specification.
You seem to be referring to the "incompletely initialised object" anti-pattern. The books I have about concurrency in Java/on the JVM strongly recommend making Java objects immutable when you can. Even in Visual Basic, if an object is "constructed" via a lengthy sequence of steps, it is good design to distinguish between two different things": a fully constructed Foo object and a FooBuilder object. Sometimes they need to be the same object, but there really do need to be two *interfaces*. Once past the construction phase, you want to KNOW that the object is fully constructed, and there are things the constructor might do that you DON'T want other objects to do. Reflecting on the use case you are talking about, it seems to be that there are two conceptually very distinct objects here. There is a FooForm object which is intimately connected to the user interface and may only partially describe a Foo, and there is a Foo object which is *not* connected to the user interface or if it is, is connected in a quite different way, exposing quite different behaviours. Reflecting further, suppose I fill out a form and press a button to commit this object, then I edit the form to be a little different, and press the button again. Creating a new *object* by revising a single *form* is clearly distinct from *editing* an existing object. What I think about this, therefore, is that you want a clear distinction between FooForms and Foos (at the very minimum a distinction between FooForm and Foo interfaces) no matter WHAT kind of programming language you are using, and I don't see Haskell as anything special here.
Let me write the same thing in other words. It is not controversial to say on this list that specifying what is correct means, is a good idea. But for GUIs, in addition to the strong type, you need another relaxed type to hold the values temporarily, until the human manages to deliver correct data, often by trial and error.
In short, we agree, that is indeed *ANOTHER* type. Not only may a FooForm not yet hold information a Foo needs, a FooForm may hold information that a Foo does *not* need. For example, a FooForm might need to hold on to some credentials to prove that it is authorised to create Foo objects, whereas a Foo object might not. In Smalltalk, Java, C#, &c one might look at ways of automatically constructing FooForms from Foo classes + annotations. Using some sort of generic processing, one could also do this in Haskell. Having two classes/types does not have to be twice as much work.

On 12.08.2014 05:31, ok@cs.otago.ac.nz wrote:
If you declare Person class in Java, you automatically get a thingy that you can readily use in UI construction, because all the fields can temporarily be null, even the required ones. In Haskell you'd need two data types: the usual proper Haskell data type, and another which wraps every field in Maybe, facilitates editing, validation, etc. Perhaps it would be possible to generate one data type from the other, or generate both from a common specification. You seem to be referring to the "incompletely initialised object" anti-pattern. The books I have about concurrency in Java/on the JVM strongly recommend making Java objects immutable when you can.
Even in Visual Basic, if an object is "constructed" via a lengthy sequence of steps, it is good design to distinguish between two different things": a fully constructed Foo object and a FooBuilder object. Sometimes they need to be the same object, but there really do need to be two *interfaces*. Once past the construction phase, you want to KNOW that the object is fully constructed, and there are things the constructor might do that you DON'T want other objects to do.
Take a VAT Invoice as an example. You will have: Invoice, InvoiceBuilder, InvoiceLineItem, InvoiceLineItemBuilder, InvoiceCustomer, InvoiceCustomerBuilder, InvoiceSummary, (no Builder, as this is calculated) (many, many more classes in a realistic system) Now, where the rather complex validation belongs? Optional / mandatory requirements, lengths, ranges, regexps, control sums, field interdependencies, autocompletes, server sent notifications? Where to put all of this? To regular classes, to builder classes, or to both? -- Wojtek

On 08/12/2014 08:55 AM, Wojtek Narczyński wrote:
On 12.08.2014 05:31, ok@cs.otago.ac.nz wrote:
If you declare Person class in Java, you automatically get a thingy that you can readily use in UI construction, because all the fields can temporarily be null, even the required ones. In Haskell you'd need two data types: the usual proper Haskell data type, and another which wraps every field in Maybe, facilitates editing, validation, etc. Perhaps it would be possible to generate one data type from the other, or generate both from a common specification. You seem to be referring to the "incompletely initialised object" anti-pattern. The books I have about concurrency in Java/on the JVM strongly recommend making Java objects immutable when you can.
Even in Visual Basic, if an object is "constructed" via a lengthy sequence of steps, it is good design to distinguish between two different things": a fully constructed Foo object and a FooBuilder object. Sometimes they need to be the same object, but there really do need to be two *interfaces*. Once past the construction phase, you want to KNOW that the object is fully constructed, and there are things the constructor might do that you DON'T want other objects to do.
Take a VAT Invoice as an example. You will have:
Invoice, InvoiceBuilder, InvoiceLineItem, InvoiceLineItemBuilder, InvoiceCustomer, InvoiceCustomerBuilder, InvoiceSummary, (no Builder, as this is calculated) (many, many more classes in a realistic system)
Now, where the rather complex validation belongs? Optional / mandatory requirements, lengths, ranges, regexps, control sums, field interdependencies, autocompletes, server sent notifications? Where to put all of this? To regular classes, to builder classes, or to both? These sound like cross-cutting concerns. I found this paper on monads and mixins for AOP.

Wojtek Narczyński
Take a VAT Invoice as an example. You will have:
Invoice, InvoiceBuilder, InvoiceLineItem, InvoiceLineItemBuilder, InvoiceCustomer, InvoiceCustomerBuilder, InvoiceSummary, (no Builder, as this is calculated) (many, many more classes in a realistic system)
Now, where the rather complex validation belongs? Optional / mandatory requirements, lengths, ranges, regexps, control sums, field interdependencies, autocompletes, server sent notifications? Where to put all of this? To regular classes, to builder classes, or to both?
The current trend in OOP Web frameworks Model-View-Controller. In MVP, Invoice/InvoiceLineItem/InvoiceCustomer/InvoiceSummary/etc. are the Model: they should form a standalone 'simulation' of an Invoice, without concerning themselves with 'external' aspects. Validation, bootstrapping (builders), etc. live in the Controller layer. If the server notifications are informing the user about the behaviour of the Model, they're part of the View. If they facilitate interaction they're part of the Controller. There are many functional styles which suit Models: - The pseudo-imperative style of Applicative/Monad/Arrow/etc. - The 'interacting streams' style, eg. infinite [(Request, Response)] lists. - Functional Reactive Programming Since Controllers can't mutate Models in Haskell, they must do one of two things: - Influence some 'future' behaviour of the Model, eg. using FRP - Build a new Model from the given settings To me the latter choice looks similar to a parsing problem. You say that Haskell's "great" at parsing, which I think contradicts your statement that "in Haskell it is unusual to deal with data that is incomplete or otherwise erroneous". In Haskell we deal with incomplete data all the time using lazy evaluation. Erroneous data doesn't require Maybes all over our data: it just needs one big Maybe in the 'parsing' function; or, more likely, "Either [Error]" detailing the problems which were found. Views are straightforward: recurse over the data, use FRP, etc. Cheers, Chris

W dniu 2014-08-12 11:30, Chris Warburton pisze:
Wojtek Narczyński
writes: ut all of this? To regular classes, to builder classes, or to both? The current trend in OOP Web frameworks Model-View-Controller. We've been doing this for 15 years, and believe me, it works only so-so. To me the latter choice looks similar to a parsing problem. You say that Haskell's "great" at parsing, which I think contradicts your statement that "in Haskell it is unusual to deal with data that is incomplete or otherwise erroneous". Grammars have been tried for GUIs, without any success. I'm not aware of any even moderate size GUI constructed this way. In Haskell we deal with incomplete data all the time using lazy evaluation. Erroneous data doesn't require Maybes all over our data: it just needs one big Maybe in the 'parsing' function; or, more likely, "Either [Error]" detailing the problems which were found.
Continuing my VAT Invoice example, let us say a LineItem that does not have a product description (missing value), but it does have all the numeric fields filled in. It is partly erroneous, but it can be included in calculation of the total. How would you handle it with Either [Error] Invoice style code? -- Cheers, Wojtek Narczyński

2014-08-12 12:46 GMT+02:00 Wojtek Narczyński
W dniu 2014-08-12 11:30, Chris Warburton pisze:
Wojtek Narczyński
writes: ut all of this? To regular classes, to builder classes, or to both?
The current trend in OOP Web frameworks Model-View-Controller.
We've been doing this for 15 years, and believe me, it works only so-so.
To me the latter choice looks similar to a parsing problem. You say that
Haskell's "great" at parsing, which I think contradicts your statement that "in Haskell it is unusual to deal with data that is incomplete or otherwise erroneous".
Grammars have been tried for GUIs, without any success. I'm not aware of any even moderate size GUI constructed this way.
Well, a formlet is essentially an applicative parser of HTTP parameters + a writer of HTML code. it works pretty well. and it can create the complete logic of a page, not only the interface if we add a monadic instance.
In Haskell we deal with incomplete data all the time using lazy
evaluation. Erroneous data doesn't require Maybes all over our data: it just needs one big Maybe in the 'parsing' function; or, more likely, "Either [Error]" detailing the problems which were found.
Continuing my VAT Invoice example, let us say a LineItem that does not have a product description (missing value), but it does have all the numeric fields filled in. It is partly erroneous, but it can be included in calculation of the total. How would you handle it with Either [Error] Invoice style code?
-- Cheers, Wojtek Narczyński
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
-- Alberto.

On Tue, Aug 12, 2014 at 12:46:05PM +0200, Wojtek Narczyński wrote:
Continuing my VAT Invoice example, let us say a LineItem that does not have a product description (missing value), but it does have all the numeric fields filled in. It is partly erroneous, but it can be included in calculation of the total. How would you handle it with Either [Error] Invoice style code?
What sort of functionality are you looking for exactly? What's your objection to (for example) data LineItemGeneral a = LineItem { price :: Price , quantity :: Quantity , description :: a } type LineItem = LineItemGeneral String type LineItemPossiblyIncomplete = LineItemGeneral (Maybe String) type LineItemWithoutDescription = LineItemGeneral () totalValue :: LineItemGeneral a -> Value totalValue lineItem = price lineItem * quantity lineItem `totalValue` works for all sorts of line items, whether they have a description or not. Tom

On 13.08.2014 12:37, Tom Ellis wrote:
On Tue, Aug 12, 2014 at 12:46:05PM +0200, Wojtek Narczyński wrote:
Continuing my VAT Invoice example, let us say a LineItem that does not have a product description (missing value), but it does have all the numeric fields filled in. It is partly erroneous, but it can be included in calculation of the total. How would you handle it with Either [Error] Invoice style code? What sort of functionality are you looking for exactly? What's your objection to (for example)
data LineItemGeneral a = LineItem { price :: Price , quantity :: Quantity , description :: a }
type LineItem = LineItemGeneral String type LineItemPossiblyIncomplete = LineItemGeneral (Maybe String) type LineItemWithoutDescription = LineItemGeneral ()
totalValue :: LineItemGeneral a -> Value totalValue lineItem = price lineItem * quantity lineItem
`totalValue` works for all sorts of line items, whether they have a description or not.
Let's say the user entered: No, Name, Qty, Price -------------------------------------------- 1. [ ] [99] [10] 2. [Water] [ ] [10] 3. [Juice] [ 1] [ ] The GUI should display total of 990, and signal four errors: three missing values (ideally different color of the input fields), and the whole invoice incomplete. The Either [Error] Invoice type does not work, because can either display the errors or calculate total from a correct invoice, never both. And you can't even create LineItem for 2. and 3. Well, maybe you can with laziness, but how would total work then? That's why I asked in my original post, whether I'd need two types, one for correct complete invoice, and another for the invoice "in statu nascendi". And how to obtain them, lazily, and I mean the person, not the language. -- Wojtek

On Wed, 13 Aug 2014 22:31:31 +0200, Wojtek Narczy?ski
Let's say the user entered:
No, Name, Qty, Price -------------------------------------------- 1. [ ] [99] [10] 2. [Water] [ ] [10] 3. [Juice] [ 1] [ ]
The GUI should display total of 990
Why? Why are any of these erroneous line items included in the total? I would argue that an incomplete or otherwise erroneous line item is not part of the invoice. I don't know of any (reasonable) online merchant that requires the user to separately enter item, quantity and price. Typically, the user interface is designed explicitly to prohibit an incomplete line item of this sort. -Steve Schafer

On 13.08.2014 22:49, Steve Schafer wrote:
On Wed, 13 Aug 2014 22:31:31 +0200, Wojtek Narczy?ski
wrote: Let's say the user entered:
No, Name, Qty, Price -------------------------------------------- 1. [ ] [99] [10] 2. [Water] [ ] [10] 3. [Juice] [ 1] [ ]
The GUI should display total of 990 Why? Why are any of these erroneous line items included in the total? I would argue that an incomplete or otherwise erroneous line item is not part of the invoice. Say that the error is merely a warning, for example the user entered 'A' which is suspiciously short. I don't know of any (reasonable) online merchant that requires the user to separately enter item, quantity and price. Yes, it is terrible. It's called "accounting".

Wojtek Narczyński
On 13.08.2014 22:49, Steve Schafer wrote:
Why? Why are any of these erroneous line items included in the total? I would argue that an incomplete or otherwise erroneous line item is not part of the invoice. Say that the error is merely a warning, for example the user entered A' which is suspiciously short.
The goalposts have moved again, although this time it's trivial: checkForWarnings :: Invoice -> [Warning] What counts as a warning, how they affect the workflow and how they're presented are business decisions. Cheers, Chris

On Wed, Aug 13, 2014 at 10:31:31PM +0200, Wojtek Narczyński wrote:
On 13.08.2014 12:37, Tom Ellis wrote:
On Tue, Aug 12, 2014 at 12:46:05PM +0200, Wojtek Narczyński wrote:
Continuing my VAT Invoice example, let us say a LineItem that does not have a product description (missing value), but it does have all the numeric fields filled in. It is partly erroneous, but it can be included in calculation of the total. How would you handle it with Either [Error] Invoice style code? What sort of functionality are you looking for exactly? What's your objection to (for example)
data LineItemGeneral a = LineItem { price :: Price , quantity :: Quantity , description :: a }
type LineItem = LineItemGeneral String type LineItemPossiblyIncomplete = LineItemGeneral (Maybe String) type LineItemWithoutDescription = LineItemGeneral ()
totalValue :: LineItemGeneral a -> Value totalValue lineItem = price lineItem * quantity lineItem
`totalValue` works for all sorts of line items, whether they have a description or not.
Let's say the user entered:
No, Name, Qty, Price -------------------------------------------- 1. [ ] [99] [10] 2. [Water] [ ] [10] 3. [Juice] [ 1] [ ]
The GUI should display total of 990, and signal four errors: three missing values (ideally different color of the input fields), and the whole invoice incomplete. The Either [Error] Invoice type does not work, because can either display the errors or calculate total from a correct invoice, never both. And you can't even create LineItem for 2. and 3. Well, maybe you can with laziness, but how would total work then?
That's why I asked in my original post, whether I'd need two types, one for correct complete invoice, and another for the invoice "in statu nascendi". And how to obtain them, lazily, and I mean the person, not the language.
Perhaps I don't grasp exactly what you're getting at, but this seems easy. Please let me know where my proposed solution fails to provide what you need. I do see that you originally said "In Haskell you'd need two data types: the usual proper Haskell data type, and another which wraps every field in Maybe, facilitates editing, validation, etc.". You don't actually *need* the version without the Maybe, but you can provide it if you want some additional type safety. If you'd like to see an example of making that nice and easy with minimal boilerplate please ask. import Control.Applicative import Data.Maybe import Control.Arrow type Quantity = Double type Price = Double type Value = Double data LineItem = LineItem { name :: Maybe String , quantity :: Maybe Quantity , price :: Maybe Price } data Field = NameField | QuantityField | PriceField deriving Show data Error = Error { item :: Int , missing :: Field } deriving Show value :: LineItem -> Maybe Value value l = (*) <$> price l <*> quantity l totalValue :: [LineItem] -> Value totalValue = sum . map (fromMaybe 0 . value) missingFields :: LineItem -> [Field] missingFields l = n ++ q ++ p where n = if name l == Nothing then [NameField] else [] q = if quantity l == Nothing then [QuantityField] else [] p = if price l == Nothing then [PriceField] else [] errors :: [LineItem] -> [Error] errors = concatMap (\(i, es) -> map (Error i) es) . zip [1..] . map missingFields guiResponse :: [LineItem] -> (Value, [Error]) guiResponse = totalValue &&& errors exampleData :: [LineItem] exampleData = [ LineItem Nothing (Just 99) (Just 10) , LineItem (Just "Water") Nothing (Just 10) , LineItem (Just "Juice") (Just 1) Nothing ] -- *Main> guiResponse exampleData -- (990.0, [ Error {item = 1, missing = NameField} -- , Error {item = 2, missing = QuantityField} -- , Error {item = 3, missing = PriceField}])

On Wed, Aug 13, 2014 at 4:21 PM, Tom Ellis < tom-lists-haskell-cafe-2013@jaguarpaw.co.uk> wrote:
On Wed, Aug 13, 2014 at 10:31:31PM +0200, Wojtek Narczyński wrote:
On 13.08.2014 12:37, Tom Ellis wrote:
On Tue, Aug 12, 2014 at 12:46:05PM +0200, Wojtek Narczyński wrote:
Continuing my VAT Invoice example, let us say a LineItem that does not have a product description (missing value), but it does have all the numeric fields filled in. It is partly erroneous, but it can be included in calculation of the total. How would you handle it with Either [Error] Invoice style code? What sort of functionality are you looking for exactly? What's your objection to (for example)
data LineItemGeneral a = LineItem { price :: Price , quantity :: Quantity , description :: a }
type LineItem = LineItemGeneral String type LineItemPossiblyIncomplete = LineItemGeneral (Maybe String) type LineItemWithoutDescription = LineItemGeneral ()
totalValue :: LineItemGeneral a -> Value totalValue lineItem = price lineItem * quantity lineItem
`totalValue` works for all sorts of line items, whether they have a description or not.
Let's say the user entered:
No, Name, Qty, Price -------------------------------------------- 1. [ ] [99] [10] 2. [Water] [ ] [10] 3. [Juice] [ 1] [ ]
The GUI should display total of 990, and signal four errors: three missing values (ideally different color of the input fields), and the whole invoice incomplete. The Either [Error] Invoice type does not work, because can either display the errors or calculate total from a correct invoice, never both. And you can't even create LineItem for 2. and 3. Well, maybe you can with laziness, but how would total work then?
That's why I asked in my original post, whether I'd need two types, one for correct complete invoice, and another for the invoice "in statu nascendi". And how to obtain them, lazily, and I mean the person, not the language.
Perhaps I don't grasp exactly what you're getting at, but this seems easy. Please let me know where my proposed solution fails to provide what you need.
I do see that you originally said "In Haskell you'd need two data types: the usual proper Haskell data type, and another which wraps every field in Maybe, facilitates editing, validation, etc.". You don't actually *need* the version without the Maybe, but you can provide it if you want some additional type safety. If you'd like to see an example of making that nice and easy with minimal boilerplate please ask.
import Control.Applicative import Data.Maybe import Control.Arrow
type Quantity = Double type Price = Double type Value = Double
data LineItem = LineItem { name :: Maybe String , quantity :: Maybe Quantity , price :: Maybe Price }
Rather than this definition, what about something like: data LineItemF f = LineItem { name :: f String , quantity :: f Quantity , price :: f Price } type LineItemBuilder = LineItemF (Writer Error) type LineItem = LineItemF Identity newLineItemBuilder :: LineItemBuilder newLineItemBuilder = LineItemF {"Missing" <$ tell (Error 1 NameField) ,0 <$ tell (Error 2 QuantityField) ,0 <$ tell (Error 3 PriceField)} setName :: LineItemBuilder -> String -> LineItemBuilder setName li newName = if validName newName then li { name = pure newName } else li -- either leave the original, or add the new name and tell another error, -- depending on use case -- quantity,price can be set similarly buildLineItem :: LineItemBuilder -> Either [Error] LineItem buildLineItem LineItemF{name, quantity,price} = case runWriter builder of (built,[]) -> Right built (_, errs) -> Left errs where builder = LineItemF <$> (pure <$> name) <*> (pure <$> quantity) <*> (pure <$> price) Now you have one type that represents a LineItem, and you can determine the state of the LineItem by which functor is used. You'll probably be able to get some code re-use for any functions that don't need to know if a particular LineItem is valid or not, but there's still a type-level distinction between validated and unvalidated LineItems. And if you're using lens, you can access the component fields with "name . _Wrapped" (or maybe _Unwrapped, depends on which version of lens you're using). If you're taking arbitrary strings as user input, and they haven't been parsed as numbers yet (or otherwise validated), you can even handle that case by using an appropriate functor, such as "Constant String". Then you could have a function like validate :: (String -> Either ValidationError a) -> Constant String a -> Either ValidationError a that takes a parser and parses/validates the field. John L.
data Field = NameField | QuantityField | PriceField deriving Show
data Error = Error { item :: Int , missing :: Field } deriving Show
value :: LineItem -> Maybe Value value l = (*) <$> price l <*> quantity l
totalValue :: [LineItem] -> Value totalValue = sum . map (fromMaybe 0 . value)
missingFields :: LineItem -> [Field] missingFields l = n ++ q ++ p where n = if name l == Nothing then [NameField] else [] q = if quantity l == Nothing then [QuantityField] else [] p = if price l == Nothing then [PriceField] else []
errors :: [LineItem] -> [Error] errors = concatMap (\(i, es) -> map (Error i) es) . zip [1..] . map missingFields
guiResponse :: [LineItem] -> (Value, [Error]) guiResponse = totalValue &&& errors
exampleData :: [LineItem] exampleData = [ LineItem Nothing (Just 99) (Just 10) , LineItem (Just "Water") Nothing (Just 10) , LineItem (Just "Juice") (Just 1) Nothing ]
-- *Main> guiResponse exampleData -- (990.0, [ Error {item = 1, missing = NameField} -- , Error {item = 2, missing = QuantityField} -- , Error {item = 3, missing = PriceField}]) _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On Wed, Aug 13, 2014 at 05:21:28PM -0700, John Lato wrote:
On Wed, Aug 13, 2014 at 4:21 PM, Tom Ellis
data LineItem = LineItem { name :: Maybe String , quantity :: Maybe Quantity , price :: Maybe Price }
Rather than this definition, what about something like:
data LineItemF f = LineItem { name :: f String , quantity :: f Quantity , price :: f Price }
It seems Wojtek already objected to this approach, though perhaps that objection could be overcome http://www.haskell.org/pipermail/haskell-cafe/2014-August/115528.html

I would suggest { someMaybeField :: f (Maybe Value) }, or perhaps newtype MaybeValue = MV (Maybe Value). On Thu, Aug 14, 2014 at 12:19 AM, Tom Ellis < tom-lists-haskell-cafe-2013@jaguarpaw.co.uk> wrote:
On Wed, Aug 13, 2014 at 05:21:28PM -0700, John Lato wrote:
On Wed, Aug 13, 2014 at 4:21 PM, Tom Ellis
data LineItem = LineItem { name :: Maybe String , quantity :: Maybe Quantity , price :: Maybe Price }
Rather than this definition, what about something like:
data LineItemF f = LineItem { name :: f String , quantity :: f Quantity , price :: f Price }
It seems Wojtek already objected to this approach, though perhaps that objection could be overcome
http://www.haskell.org/pipermail/haskell-cafe/2014-August/115528.html _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On Thu, Aug 14, 2014 at 01:35:36AM -0700, John Lato wrote:
I would suggest { someMaybeField :: f (Maybe Value) }, or perhaps newtype MaybeValue = MV (Maybe Value).
That seems like a perfectly good solution to me. The only drawback is that you cannot validate fields individually. Tom

On 14.08.2014 09:19, Tom Ellis wrote:
On Wed, Aug 13, 2014 at 05:21:28PM -0700, John Lato wrote:
On Wed, Aug 13, 2014 at 4:21 PM, Tom Ellis
data LineItem = LineItem { name :: Maybe String , quantity :: Maybe Quantity , price :: Maybe Price }
Rather than this definition, what about something like:
data LineItemF f = LineItem { name :: f String , quantity :: f Quantity , price :: f Price } It seems Wojtek already objected to this approach, though perhaps that objection could be overcome
Hmm, perhaps like this LineItemFi = LineItemFi { name :: StringFi , quantity :: QuantityFi , price :: PriceFi } data LineItemUi f = LineItemUi { name :: StringUi , quantity :: QuantityUi , price :: PriceUi } I mean 1:1 correspondence between leaf UI types that can be missing, validate lengths, etc. and final types that go to the backend. Maybe it would be possible to use type classes / families to have common arithmietics for calculating with both kinds of types. This does require TH or Generics, but it's fine. -- Wojtek

On Thu, Aug 14, 2014 at 11:28:53AM +0200, Wojtek Narczyński wrote:
On 14.08.2014 09:19, Tom Ellis wrote:
On Wed, Aug 13, 2014 at 05:21:28PM -0700, John Lato wrote:
On Wed, Aug 13, 2014 at 4:21 PM, Tom Ellis
data LineItem = LineItem { name :: Maybe String , quantity :: Maybe Quantity , price :: Maybe Price }
Rather than this definition, what about something like:
data LineItemF f = LineItem { name :: f String , quantity :: f Quantity , price :: f Price } It seems Wojtek already objected to this approach, though perhaps that objection could be overcome
Hmm, perhaps like this
LineItemFi = LineItemFi { name :: StringFi , quantity :: QuantityFi , price :: PriceFi }
data LineItemUi f = LineItemUi { name :: StringUi , quantity :: QuantityUi , price :: PriceUi }
You didn't use f there.

Formlets ever had cascade validation: data Item= Item{ name ::String, quantity, price :: Int} Item <$> <*> inputString `validate` nonEmpty <*> inputInt <*> inputInt `validate` ( \item -> do if theUniverseIsSpanding then do if name item == "carrots" && price=="10" then fail "we don´t like 10 cent carrots in an expanding universe" else if..... 2014-08-14 11:41 GMT+02:00 Tom Ellis < tom-lists-haskell-cafe-2013@jaguarpaw.co.uk>:
On Thu, Aug 14, 2014 at 11:28:53AM +0200, Wojtek Narczyński wrote:
On 14.08.2014 09:19, Tom Ellis wrote:
On Wed, Aug 13, 2014 at 05:21:28PM -0700, John Lato wrote:
On Wed, Aug 13, 2014 at 4:21 PM, Tom Ellis
data LineItem = LineItem { name :: Maybe String , quantity :: Maybe Quantity , price :: Maybe Price }
Rather than this definition, what about something like:
data LineItemF f = LineItem { name :: f String , quantity :: f Quantity , price :: f Price } It seems Wojtek already objected to this approach, though perhaps that objection could be overcome
Hmm, perhaps like this
LineItemFi = LineItemFi { name :: StringFi , quantity :: QuantityFi , price :: PriceFi }
data LineItemUi f = LineItemUi { name :: StringUi , quantity :: QuantityUi , price :: PriceUi }
You didn't use f there. _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
-- Alberto.

This is starting to look promising. I think what would be really
interesting would be to abstract out the validation logic so that it could
be presented in a more declarative fashion, something like
itemPrice *> \item inputPrice ->
if inputPrice > 0 then return inputPrice
else fail ("invalid item price for item " ++ show
(item,inputPrice))
itemTotal *> \item _ -> do
price <- need $ itemPrice item
qty <- need $ itemQty item
return $ price * qty
itemizedVat *> \item _ -> do
vatExempt <- need $ vatStatus . client . invoice $ item
if vatExempt then return 0 else do
total <- need $ itemTotal item
rate <- need $ vatRate item
return $ calcVatForValue total rate
total *> \invoice _ -> do
itemTotals <- forM (items invoice) $ \item -> (,) <$> need
(itemTotal item) <*> need (itemizedVat item)
let (itemVals,vatVals) = unzip itemTotals
subTotal = sum itemVals
vatTotal = sum vatVals
return $ Total { subTotal, vatTotal, fullTotal = subTotal+vatTotal }
Inspired by the shake build system. Off the top of my head, so there's no
system I know of that implements something like this. But it might be a
nice way to declare complex validation rules, perhaps? Error handling
could be handled by individual rules, so we know if there's a valid
itemPrice and itemQty, the itemTotal is valid too.
It might be tricky to implement this exactly as-is, I'm using "itemTotal"
as both a tag to specify a rule match and also a field name. And typing
some of the input/output stuff might be non-trivial. Seems like something
that could benefit from a specialized DSL.
John L.
On Thu, Aug 14, 2014 at 5:06 AM, Alberto G. Corona
Formlets ever had cascade validation:
data Item= Item{ name ::String, quantity, price :: Int}
Item <$> <*> inputString `validate` nonEmpty <*> inputInt <*> inputInt `validate` ( \item -> do if theUniverseIsSpanding then do if name item == "carrots" && price=="10" then fail "we don´t like 10 cent carrots in an expanding universe" else if.....
2014-08-14 11:41 GMT+02:00 Tom Ellis < tom-lists-haskell-cafe-2013@jaguarpaw.co.uk>:
On Thu, Aug 14, 2014 at 11:28:53AM +0200, Wojtek Narczyński wrote:
On 14.08.2014 09:19, Tom Ellis wrote:
On Wed, Aug 13, 2014 at 05:21:28PM -0700, John Lato wrote:
On Wed, Aug 13, 2014 at 4:21 PM, Tom Ellis
data LineItem = LineItem { name :: Maybe String , quantity :: Maybe Quantity , price :: Maybe Price }
Rather than this definition, what about something like:
data LineItemF f = LineItem { name :: f String , quantity :: f Quantity , price :: f Price } It seems Wojtek already objected to this approach, though perhaps that objection could be overcome
Hmm, perhaps like this
LineItemFi = LineItemFi { name :: StringFi , quantity :: QuantityFi , price :: PriceFi }
data LineItemUi f = LineItemUi { name :: StringUi , quantity :: QuantityUi , price :: PriceUi }
You didn't use f there. _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
-- Alberto.
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On 14.08.2014 01:21, Tom Ellis wrote:
Perhaps I don't grasp exactly what you're getting at, but this seems easy. Please let me know where my proposed solution fails to provide what you need.
I do see that you originally said "In Haskell you'd need two data types: the usual proper Haskell data type, and another which wraps every field in Maybe, facilitates editing, validation, etc.". You don't actually *need* the version without the Maybe, but you can provide it if you want some additional type safety.
Yes! This is what I mean. But there is much more to validation, than just missing values. For text fields you have lengths, regexps. For numeric fields you have ranges, steps. Then come rules that are inter-fleld: if this field is "Yes", that field must be filled, if the user chooses "No" a field should be hidden, if the user changes his mind, the value entered should be preserved (not validation, but related). Then come rules that are inter-record: if this field is "ExportInvoice", all VAT fields in the LineItem must be zero. The difficulty lies in abundance, ubiquity and complexity of the validation rules. Empty fields are just an innocent example. The code you provided solves it well, but this is just a tip of an iceberg. And we still haven't even touched the subject of assisting the user to fix the inconsistencies. Therefore, quite frankly, I was hoping for radical new ideas how to tackle this, when I was starting this thread. DSLs, logic, Attribute Grammars, something like that.

On Thu, Aug 14, 2014 at 10:48:34AM +0200, Wojtek Narczyński wrote:
On 14.08.2014 01:21, Tom Ellis wrote:
Perhaps I don't grasp exactly what you're getting at, but this seems easy. Please let me know where my proposed solution fails to provide what you need.
I do see that you originally said "In Haskell you'd need two data types: the usual proper Haskell data type, and another which wraps every field in Maybe, facilitates editing, validation, etc.". You don't actually *need* the version without the Maybe, but you can provide it if you want some additional type safety.
Yes! This is what I mean.
But there is much more to validation, than just missing values. [...]
The difficulty lies in abundance, ubiquity and complexity of the validation rules.
Empty fields are just an innocent example. The code you provided solves it well, but this is just a tip of an iceberg.
And we still haven't even touched the subject of assisting the user to fix the inconsistencies.
Therefore, quite frankly, I was hoping for radical new ideas how to tackle this, when I was starting this thread. DSLs, logic, Attribute Grammars, something like that.
Is there a language that gets this right? If so we can try replicating its functionality in Haskell. Tom

Let's say the user entered:
No, Name, Qty, Price -------------------------------------------- 1. [ ] [99] [10] 2. [Water ] [ ] [10] 3. [Juice ] [ 1] [ ]
The GUI should display total of 990,
Why? Let's be clear about this: given that information, the total is unknown and unknowable, and even if lines 1 and 2 were intended to be the same line, the existence of line 3 means that 990 is almost surely LESS than the correct total, whatever that might be. Supermarkets here don't let you create invoice lines by reference (giving a possibly garbled name) but only by ostension ("I want to buy THIS"). This is why all those bar codes and thingies exist. Libraries here do something similar with books: you show the machine "I want to borrow THIS book" and a guaranteed valid line is created. A GUI clearly *could* be designed to allow badly messed up entries like that, but it is at least questionable whether it *should*. A possible data point: students here are very much used to the instant feedback provided by syntax colouring editors, and few of them would willingly program without such tools. (I'm annoyed by and slowed by this nonsense, but tastes vary.) This is evidence that at least some people strongly prefer instant feedback; by the time they get to the end of a form they know that each and every field is at least plausible taken by itself. and signal four errors: three
missing values (ideally different color of the input fields), and the whole invoice incomplete. The Either [Error] Invoice type does not work, because can either display the errors or calculate total from a correct invoice, never both. And you can't even create LineItem for 2. and 3. Well, maybe you can with laziness, but how would total work then?
That's why I asked in my original post, whether I'd need two types, one for correct complete invoice, and another for the invoice "in statu nascendi". And how to obtain them, lazily, and I mean the person, not the language.
-- Wojtek _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On 14.08.2014 03:22, ok@cs.otago.ac.nz wrote:
Let's say the user entered:
No, Name, Qty, Price -------------------------------------------- 1. [ ] [99] [10] 2. [Water ] [ ] [10] 3. [Juice ] [ 1] [ ]
The GUI should display total of 990, Why? Let's be clear about this: given that information, the total is unknown and unknowable, and even if lines 1 and 2 were intended to be the same line, the existence of line 3 means that 990 is almost surely LESS than the correct total, whatever that might be.
Because this is what you would get in the most familiar software for accountants, and the most widespread functional language in the world: a spreadsheet. Or simply because this has been specified this way and the developer is supposed to implement it.
Supermarkets here don't let you create invoice lines by reference (giving a possibly garbled name) but only by ostension ("I want to buy THIS"). This is why all those bar codes and thingies exist. Libraries here do something similar with books: you show the machine "I want to borrow THIS book" and a guaranteed valid line is created.
Imagine you are a freelance programmer and you are in the process of invoicing your customer.
A possible data point: students here are very much used to the instant feedback provided by syntax colouring editors, and few of them would willingly program without such tools. (I'm annoyed by and slowed by this nonsense, but tastes vary.) Heh, I also like syntax colouring editors, vim specifically. Recently I saw SublimeText, and I also liked it very much, I almost switched from vim. I keep promising to myself that I would learn Emacs. I don't like Eclipse, because it is too slow.
This is evidence that at least some people strongly prefer instant feedback; by the time they get to the end of a form they know that each and every field is at least plausible taken by itself.
So in the end you admit that my "design" (scratch, rather) might be what young people might like? -- Kind regards, Wojtek Narczynski

On 14.08.2014 03:22, ok@cs.otago.ac.nz wrote:
Let's say the user entered:
No, Name, Qty, Price -------------------------------------------- 1. [ ] [99] [10] 2. [Water ] [ ] [10] 3. [Juice ] [ 1] [ ]
The GUI should display total of 990, Why? Let's be clear about this: given that information, the total is unknown and unknowable, and even if lines 1 and 2 were intended to be the same line, the existence of line 3 means that 990 is almost surely LESS than the correct total, whatever that might be.
Because this is what you would get in the most familiar software for accountants, and the most widespread functional language in the world: a spreadsheet. Or simply because this has been specified this way and the developer is supposed to implement it.
You have taught me something, and I am grateful for the lesson, and APPALLED at the contents of the lesson. I don't use spreadsheets, so I was unaware of this gross and horrifying bug in them. There is no excuse for a spreadsheet quietly taking a never-assigned cell as zero, but indeed it does. WHAT THE HELL WERE THESE PEOPLE SMOKING? It may be familiar, it may be popular, but the answer is beyond any reasonable question simply WRONG. As for "the developer is supposed to implement it", next week I'll be giving my annual ethics lecture and I'll be pointing out to students that the codes of practice of the various professional societies all agree that your duty goes beyond simply doing what you are told. If you are told to write consumer software that gets its sums wrong, you should not do it. However, in this context, all that matters is that you actually have TWO senses of "valid". Data may be valid-for-sums, where missing data are defined (wrongly, but that's your spec.) to be zero, without actually being honest-to-goodness-valid. The question remains whether this valid-for-sums processing is a property of *invoices* or a property of *forms*, and I claim that it's a property of invoice *forms* but not a property of invoices. That's one way to distinguish between valid-for-spreadsheet-sums and honest-to-goodness-valid. There are others. Panko's paper, "What we know about spreadsheet errors" http://panko.shidler.hawaii.edu/SSR/Mypapers/whatknow.htm has some scary numbers. It contains these sentences: In 2003, the author spoke independently with experienced spreadsheet auditors in two different companies in the United Kingdom, where certain spreadsheets must be audited by law. Each audited about three dozen spreadsheets per year. Both said that they had NEVER seen a major spreadsheet that was free of errors Both also indicated that about five percent of the spreadsheets they audited have very serious errors that would have had major ramifications had they not been caught. (The emphasis on NEVER is mine.) I guess now we know one more reason why spreadsheet errors are ubiquitous: the interface is broken by design.
Imagine you are a freelance programmer and you are in the process of invoicing your customer.
I have no idea what is customary, but I for d--n sure would not use a spreadsheet to do it! (This being a Haskell mailing list, I would investigate the abilities of hLedger.)
This is evidence that at least some people strongly prefer instant feedback; by the time they get to the end of a form they know that each and every field is at least plausible taken by itself.
So in the end you admit that my "design" (scratch, rather) might be what young people might like?
On the contrary. You are specifying a design that lets invalid data enter into computations. I'm saying they would like a design that stops invalid data as early as possible. This is close in spirit to the Foo/FooBuilder distinction, where a Foo is never allowed to be in an invalid state.

On 14.08.2014 16:44, ok@cs.otago.ac.nz wrote:
It may be familiar, it may be popular, but the answer is beyond any reasonable question simply WRONG.
The exactly advantage of a purpose built app over a spreadsheet is that it would not let you save the invoice in this state. Indeed, perhaps it is a good idea to tell the users that this sum is not their final value. For example display a marijuana leaf next to it. Although, I would rather use color for that.
(The emphasis on NEVER is mine.) I guess now we know one more reason why spreadsheet errors are ubiquitous: the interface is broken by design.
I like spreadsheets, but they are not an answer to every need.
I have no idea what is customary, but I for d--n sure would not use a spreadsheet to do it! (This being a Haskell mailing list, I would investigate the abilities of hLedger.)
Sorry, hledger is a double entry accounting system, it does not issue invoices.
So in the end you admit that my "design" (scratch, rather) might be what young people might like? On the contrary. You are specifying a design that lets invalid data enter into computations. I'm saying they would like a design that stops invalid data as early as possible. This is close in spirit to the Foo/FooBuilder distinction, where a Foo is never allowed to be in an invalid state.
Pardon me, but are you "young people"?

Would't this be a good solution to the partial null fields probleme?
--The field name and the value
type Field = (String,String)
--The form informations we get from the client
type FormResult = [Filed]
--An error message to send to teh client
type FormError = String
data Person = Person {
firstName :: String
,lastName :: String
,birthDate :: Date
,height :: Int
}
type PersonParseResult = Either FormError Person
--When receiving data froom the client you call this function and return
the error to the client or continue normaly
getPersonneFromForm :: FormResult -> PersonParseResult
--You could go furter and do this:
class FromForm a where
fromForm :: FormResult -> Either FormError a
instance FromForm Person where
fromForm a = getPersonneFromForm a
--And then you could do this:
thisFunctionGetAForm :: FormResult -> HTTPResponse
thisFunctionGetAForm f =
case (fromForm f) :: PersonParseResult of
Left a -> toHTTPResponse "The form is invalid"
Right a -> toHTTPResponse "Ok, we got you"
2014-08-14 11:11 GMT-04:00 Wojtek Narczyński
On 14.08.2014 16:44, ok@cs.otago.ac.nz wrote:
It may be familiar, it may be popular, but the answer is beyond any reasonable question simply WRONG.
The exactly advantage of a purpose built app over a spreadsheet is that it would not let you save the invoice in this state. Indeed, perhaps it is a good idea to tell the users that this sum is not their final value. For example display a marijuana leaf next to it. Although, I would rather use color for that.
(The emphasis on NEVER is mine.) I guess now we know one
more reason why spreadsheet errors are ubiquitous: the interface is broken by design.
I like spreadsheets, but they are not an answer to every need.
I have no idea what is customary, but I for d--n sure would not use a spreadsheet to do it! (This being a Haskell mailing list, I would investigate the abilities of hLedger.)
Sorry, hledger is a double entry accounting system, it does not issue invoices.
So in the end you admit that my "design" (scratch, rather) might be what
young people might like?
On the contrary. You are specifying a design that lets invalid data enter into computations. I'm saying they would like a design that stops invalid data as early as possible. This is close in spirit to the Foo/FooBuilder distinction, where a Foo is never allowed to be in an invalid state.
Pardon me, but are you "young people"?
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
-- Viva Cila

W dniu 2014-08-14 19:22, Raphaël Mongeau pisze:
Would't this be a good solution to the partial null fields probleme?
It is a solution to the null problem alone. But it is not a holistic way to create good GUIs. For example id doesn't touch the following problems: checking input for legal characters, text field lengths, numeric ranges, inter-field dependencies, inter-record dependencies, undo, saving partially filled forms to finish filling them in later, and probably many more. Also, I'm after something in the spirit of Alberto's hplayground. For the web UI to be appealing nowadays, it has to work on the client. http://mflowdemo.herokuapp.com/noscript/wiki/browserwidgets https://github.com/agocorona/hplayground -- Wojtek

There is no excuse for a spreadsheet quietly taking a never-assigned cell as zero, but indeed it does.
May I contribute to this interesting discussion the observation:
1
<BLANK>
3
=PRODUCT(A1:A3)
gives 3 (in Gnumeric).
So for the PRODUCT function, blanks are treated as 1.
Furthermore, you may be interested in priorknowledge's techcrunch talk in
which they promised to "disrupt blanks":
http://techcrunch.com/2012/09/11/prior-knowledge-a-predictive-database-for-d...
Tom
On Thu, Aug 14, 2014 at 3:44 PM,
On 14.08.2014 03:22, ok@cs.otago.ac.nz wrote:
Let's say the user entered:
No, Name, Qty, Price -------------------------------------------- 1. [ ] [99] [10] 2. [Water ] [ ] [10] 3. [Juice ] [ 1] [ ]
The GUI should display total of 990, Why? Let's be clear about this: given that information, the total is unknown and unknowable, and even if lines 1 and 2 were intended to be the same line, the existence of line 3 means that 990 is almost surely LESS than the correct total, whatever that might be.
Because this is what you would get in the most familiar software for accountants, and the most widespread functional language in the world: a spreadsheet. Or simply because this has been specified this way and the developer is supposed to implement it.
You have taught me something, and I am grateful for the lesson, and APPALLED at the contents of the lesson. I don't use spreadsheets, so I was unaware of this gross and horrifying bug in them. There is no excuse for a spreadsheet quietly taking a never-assigned cell as zero, but indeed it does. WHAT THE HELL WERE THESE PEOPLE SMOKING?
It may be familiar, it may be popular, but the answer is beyond any reasonable question simply WRONG.
As for "the developer is supposed to implement it", next week I'll be giving my annual ethics lecture and I'll be pointing out to students that the codes of practice of the various professional societies all agree that your duty goes beyond simply doing what you are told. If you are told to write consumer software that gets its sums wrong, you should not do it.
However, in this context, all that matters is that you actually have TWO senses of "valid". Data may be valid-for-sums, where missing data are defined (wrongly, but that's your spec.) to be zero, without actually being honest-to-goodness-valid.
The question remains whether this valid-for-sums processing is a property of *invoices* or a property of *forms*, and I claim that it's a property of invoice *forms* but not a property of invoices.
That's one way to distinguish between valid-for-spreadsheet-sums and honest-to-goodness-valid. There are others.
Panko's paper, "What we know about spreadsheet errors" http://panko.shidler.hawaii.edu/SSR/Mypapers/whatknow.htm has some scary numbers. It contains these sentences:
In 2003, the author spoke independently with experienced spreadsheet auditors in two different companies in the United Kingdom, where certain spreadsheets must be audited by law. Each audited about three dozen spreadsheets per year. Both said that they had NEVER seen a major spreadsheet that was free of errors Both also indicated that about five percent of the spreadsheets they audited have very serious errors that would have had major ramifications had they not been caught.
(The emphasis on NEVER is mine.) I guess now we know one more reason why spreadsheet errors are ubiquitous: the interface is broken by design.
Imagine you are a freelance programmer and you are in the process of invoicing your customer.
I have no idea what is customary, but I for d--n sure would not use a spreadsheet to do it! (This being a Haskell mailing list, I would investigate the abilities of hLedger.)
This is evidence that at least some people strongly prefer instant feedback; by the time they get to the end of a form they know that each and every field is at least plausible taken by itself.
So in the end you admit that my "design" (scratch, rather) might be what young people might like?
On the contrary. You are specifying a design that lets invalid data enter into computations. I'm saying they would like a design that stops invalid data as early as possible. This is close in spirit to the Foo/FooBuilder distinction, where a Foo is never allowed to be in an invalid state.
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On 15.08.2014 16:17, Tom Nielsen wrote:
There is no excuse for a spreadsheet quietly taking a never-assigned cell as zero, but indeed it does.
May I contribute to this interesting discussion the observation:
1 <BLANK> 3 =PRODUCT(A1:A3)
gives 3 (in Gnumeric).
So for the PRODUCT function, blanks are treated as 1.
At the same time = A1 * A2 * A3 gives 0 (in OpenOffice). This is a bit too much, even for me.

On 12.08.2014 05:31, ok@cs.otago.ac.nz wrote:
Even in Visual Basic, if an object is "constructed" via a lengthy sequence of steps, it is good design to distinguish between two different things": a fully constructed Foo object and a FooBuilder object. Sometimes they need to be the same object, but there really do need to be two *interfaces*. Once past the construction phase, you want to KNOW that the object is fully constructed, and there are things the constructor might do that you DON'T want other objects to do.
Take a VAT Invoice as an example. You will have:
Invoice, InvoiceBuilder, InvoiceLineItem, InvoiceLineItemBuilder, InvoiceCustomer, InvoiceCustomerBuilder, InvoiceSummary, (no Builder, as this is calculated) (many, many more classes in a realistic system)
Now, where the rather complex validation belongs?
Follow the GRASP patterns. Give the task to the type/class that has enough information to do the job. Remember, the goal is to not create invalid objects. It makes no sense to have an Invoice validate itself, because the whole aim is for invalid Invoices NEVER TO EXIST. Some validation is fairly shallow. If you can check a field as soon as it is typed, it might make sense to do so. (Or it might not. That's a user interface design question.) Some validation is deeper, and can only be done once you have full or nearly full information. The obvious place to put deeper validation is InvoiceBuilder; that, after all, is one of the principal reasons to *have* an InvoiceBuilder. By the way, I deny that you would have a delirious menagerie of _Builder classes, as you seem to be implying. There needs to be something *separate* from an InvoiceLineItem that can accumulate the information needed to build one, and can validate that information before the thing is built, but an InvoiceBuilder can take responsibility for building all the components of an Invoice. So which types/classes deserve their own _Builder and which do not? - First, the _Builder pattern applies for things that have to be built up *incrementally* and may be in incomplete or inconsistent states while they are being built. If you can construct something all at once in a fully valid state, you should, and don't need a Builder. If you can build something in a complete valid state and then you want to revise it as part of normal operation, again you don't need a builder. - Second, some things are "free-standing" and some only make sense as part of other things. I'm not sure exactly what you have in mind by an InvoiceSummary, but let's assume that an InvoiceSummary belongs to one and only one Invoice and that it doesn't really make sense for an InvoiceSummary to exist on its own. Then it can share its owner's Builder. In OO terms, the pattern goes something like this: program creates an InvoiceBuilder x filling out and revising the form revises x. there is a "commit" button; when x processes that, it creates a new Invoice y. y fills itself in, calling back to x to get the information it needs. y may create its dependents; in fact, since a dependent should be *born* knowing what it depends on, the dependents *can't* be created until y exists. So it probably should be y that does the creation. Eventually y finishes initialising itself, and x is now able to make y visible elsewhere. The term "Builder" may be a bit misleading: the job of a Builder is to *accumulate the information needed for complete construction*; the actual work of construction may be done by the new object that is eventually created, including the creation of its parts. The key thing is that *incompletely or inconsistently objects are never exposed*; the first time a thing is mentionable, it is right.
Optional / mandatory requirements, lengths, ranges, regexps, control sums, field interdependencies, autocompletes, server sent notifications? Where to put all of this? To regular classes, to builder classes, or to both?
There are two and only two honest answers to questions like that. (A) This sounds like carping, not like a real question. (B) "It depends." Put it wherever it works best. Invoices are actually a nice example. I had a student once who told me a bit about SAP. (He made a lot more money as a SAP expert than I make as a lecturer.) As I understand it, one of the key reasons to use SAP is that once a record has gone into the data base, it cannot be changed or deleted. It can be marked as not to be used any more, but it can't go away. It can be marked as having been superseded by a corrected version, but it can't be changed. So if you want to create an invoice in SAP, you really really want to use the Builder pattern (at least in spirit). Once the various tuples that constitute the Invoice have been inserted in the data base, changing them is very far from being normal operation. For SAP, at least, I can say "put all those things anywhere you like EXCEPT in the (persistent) Invoice." And of course in the real world, if you are old enough you have had the experience of interacting with an InvoiceBuilder. You the customer, in the act of buying carpet, are sitting on one side of the desk. On the desk is the Invoice. On the other side of the desk is the InvoiceBuilder, otherwise known as "a salesman", who gathers information from you, and fills in the invoice. You don't interact with the Invoice. It just sits there. Once the Invoice leaves the desk, the information on it normally should not change. If it is to change, a corrected duplicate is made, the old one crossed out, and the new one stapled to it. Doing this might even require the customer's signature on the new one. The rest of the business only deals with complete Invoices. Of course, it _all_ depends. If you are whipping up a prototype and speed of development (so you can get to answer some high-risk question soon) is a priority, cut all the corners you think appropriate.

On 12.08.2014 05:31, ok@cs.otago.ac.nz wrote:
Even in Visual Basic, if an object is "constructed" via a lengthy sequence of steps, it is good design to distinguish between two different things": a fully constructed Foo object and a FooBuilder object. Sometimes they need to be the same object, but there really do need to be two *interfaces*. Once past the construction phase, you want to KNOW that the object is fully constructed, and there are things the constructor might do that you DON'T want other objects to do.
Take a VAT Invoice as an example. You will have:
Invoice, InvoiceBuilder, InvoiceLineItem, InvoiceLineItemBuilder, InvoiceCustomer, InvoiceCustomerBuilder, InvoiceSummary, (no Builder, as this is calculated) (many, many more classes in a realistic system)
Now, where the rather complex validation belongs?
Follow the GRASP patterns. Give the task to the type/class that has enough information to do the job. Remember, the goal is to not create invalid objects. It makes no sense to have an Invoice validate itself, because the whole aim is for invalid Invoices NEVER TO EXIST. Some validation is fairly shallow. If you can check a field as soon as it is typed, it might make sense to do so. (Or it might not. That's a user interface design question.) Some validation is deeper, and can only be done once you have full or nearly full information. The obvious place to put deeper validation is InvoiceBuilder; that, after all, is one of the principal reasons to *have* an InvoiceBuilder. By the way, I deny that you would have a delirious menagerie of _Builder classes, as you seem to be implying. There needs to be something *separate* from an InvoiceLineItem that can accumulate the information needed to build one, and can validate that information before the thing is built, but an InvoiceBuilder can take responsibility for building all the components of an Invoice. So which types/classes deserve their own _Builder and which do not? - First, the _Builder pattern applies for things that have to be built up *incrementally* and may be in incomplete or inconsistent states while they are being built. If you can construct something all at once in a fully valid state, you should, and don't need a Builder. If you can build something in a complete valid state and then you want to revise it as part of normal operation, again you don't need a builder. - Second, some things are "free-standing" and some only make sense as part of other things. I'm not sure exactly what you have in mind by an InvoiceSummary, but let's assume that an InvoiceSummary belongs to one and only one Invoice and that it doesn't really make sense for an InvoiceSummary to exist on its own. Then it can share its owner's Builder. In OO terms, the pattern goes something like this: program creates an InvoiceBuilder x filling out and revising the form revises x. there is a "commit" button; when x processes that, it creates a new Invoice y. y fills itself in, calling back to x to get the information it needs. y may create its dependents; in fact, since a dependent should be *born* knowing what it depends on, the dependents *can't* be created until y exists. So it probably should be y that does the creation. Eventually y finishes initialising itself, and x is now able to make y visible elsewhere. The term "Builder" may be a bit misleading: the job of a Builder is to *accumulate the information needed for complete construction*; the actual work of construction may be done by the new object that is eventually created, including the creation of its parts. The key thing is that *incompletely or inconsistently objects are never exposed*; the first time a thing is mentionable, it is right.
Optional / mandatory requirements, lengths, ranges, regexps, control sums, field interdependencies, autocompletes, server sent notifications? Where to put all of this? To regular classes, to builder classes, or to both?
There are two and only two honest answers to questions like that. (A) This sounds like carping, not like a real question. (B) "It depends." Put it wherever it works best. Invoices are actually a nice example. I had a student once who told me a bit about SAP. (He made a lot more money as a SAP expert than I make as a lecturer.) As I understand it, one of the key reasons to use SAP is that once a record has gone into the data base, it cannot be changed or deleted. It can be marked as not to be used any more, but it can't go away. It can be marked as having been superseded by a corrected version, but it can't be changed. So if you want to create an invoice in SAP, you really really want to use the Builder pattern (at least in spirit). Once the various tuples that constitute the Invoice have been inserted in the data base, changing them is very far from being normal operation. For SAP, at least, I can say "put all those things anywhere you like EXCEPT in the (persistent) Invoice." And of course in the real world, if you are old enough you have had the experience of interacting with an InvoiceBuilder. You the customer, in the act of buying carpet, are sitting on one side of the desk. On the desk is the Invoice. On the other side of the desk is the InvoiceBuilder, otherwise known as "a salesman", who gathers information from you, and fills in the invoice. You don't interact with the Invoice. It just sits there. Once the Invoice leaves the desk, the information on it normally should not change. If it is to change, a corrected duplicate is made, the old one crossed out, and the new one stapled to it. Doing this might even require the customer's signature on the new one. The rest of the business only deals with complete Invoices. Of course, it _all_ depends. If you are whipping up a prototype and speed of development (so you can get to answer some high-risk question soon) is a priority, cut all the corners you think appropriate.

On 13.08.2014 03:27, ok@cs.otago.ac.nz wrote:
By the way, I deny that you would have a delirious menagerie of _Builder classes, as you seem to be implying. So how exactly would you store InvoiceLine-wannabe, Customer-wannabe, and the like, objects inside InvoiceBuilder? OO always has the same answer: more patterns, more classes. This is not OO list, so hereby I declare not to continue this fork of this thread.
Regarding SAP, ABAP is in fact a nice DSL, but did he also tell you that all the custom procedure names must start from 'Z'? (VAT) Invoice, is a good example, I wish it were used more often, in addition to the TODO list. -- Kind regards from the other side of Earth, Wojtek Narczyński

I think the way Jon Sterling integrated validation in his extensible
library might give some inspiration about using a similar approach to solve
the specific problem you describe.
He did a great talk about it recently, I highly recommend it:
http://t.co/ZKceAY5zAz
Cheers
Alois
On 11 August 2014 23:16, Wojtek Narczyński
Dear All,
Haskell is great for great many areas, let me name just two: - parsers, translators, interpreters, compilers; highly concurrent systems.
Haskell is however not great for GUIs. I've been thinking a little why this is so. I think one of the reasons might be that in Haskell it is unusual to deal with data that is incomplete or otherwise erroneous. Let me try to explain, what I mean, by example. If you declare Person class in Java, you automatically get a thingy that you can readily use in UI construction, because all the fields can temporarily be null, even the required ones. In Haskell you'd need two data types: the usual proper Haskell data type, and another which wraps every field in Maybe, facilitates editing, validation, etc. Perhaps it would be possible to generate one data type from the other, or generate both from a common specification.
Let me write the same thing in other words. It is not controversial to say on this list that specifying what is correct means, is a good idea. But for GUIs, in addition to the strong type, you need another relaxed type to hold the values temporarily, until the human manages to deliver correct data, often by trial and error.
Comments welcome.
-- Kind regards, Wojtek Narczyński
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
-- *Λ\ois* http://twitter.com/aloiscochard http://github.com/aloiscochard

On 11 Aug 2014, at 23:16, Wojtek Narczyński
If you declare Person class in Java, you automatically get a thingy that you can readily use in UI construction, because all the fields can temporarily be null, even the required ones. In Haskell you'd need two data types: the usual proper Haskell data type, and another which wraps every field in Maybe, facilitates editing, validation, etc. Perhaps it would be possible to generate one data type from the other, or generate both from a common specification.
At least this part you can achieve rather easily by parametrizing each field in your record by a functor. E.g.: data Person f = Person { firstName :: f String ,lastName :: f String ,birthDate :: f Date ,height :: f Int } Then you get: - "Person Id" is a person with every field set in stone. - "Person Maybe" is a person with missing information. - Other functors can be easily defined (and then composed) to represent things such as Mandatory/Optional, Valid/Invalid, etc.

W dniu 2014-08-12 15:01, Daniel Gorín pisze:
On 11 Aug 2014, at 23:16, Wojtek Narczyński
wrote: If you declare Person class in Java, you automatically get a thingy that you can readily use in UI construction, because all the fields can temporarily be null, even the required ones. In Haskell you'd need two data types: the usual proper Haskell data type, and another which wraps every field in Maybe, facilitates editing, validation, etc. Perhaps it would be possible to generate one data type from the other, or generate both from a common specification. At least this part you can achieve rather easily by parametrizing each field in your record by a functor. E.g.:
data Person f = Person { firstName :: f String ,lastName :: f String ,birthDate :: f Date ,height :: f Int }
Then you get:
- "Person Id" is a person with every field set in stone.
- "Person Maybe" is a person with missing information.
- Other functors can be easily defined (and then composed) to represent things such as Mandatory/Optional, Valid/Invalid, etc.
I saw in the presentation submitted in another post that a similar thing has been done in Vinyl. But this won't work so well, because in the "rigid" type some fields are still supposed to remain wrapped in Maybe. -- Wojtek

On 12 Aug 2014, at 20:23, Wojciech Narczyński
W dniu 2014-08-12 15:01, Daniel Gorín pisze:
On 11 Aug 2014, at 23:16, Wojtek Narczyński
wrote: If you declare Person class in Java, you automatically get a thingy that you can readily use in UI construction, because all the fields can temporarily be null, even the required ones. In Haskell you'd need two data types: the usual proper Haskell data type, and another which wraps every field in Maybe, facilitates editing, validation, etc. Perhaps it would be possible to generate one data type from the other, or generate both from a common specification. At least this part you can achieve rather easily by parametrizing each field in your record by a functor. E.g.:
data Person f = Person { firstName :: f String ,lastName :: f String ,birthDate :: f Date ,height :: f Int }
Then you get:
- "Person Id" is a person with every field set in stone.
- "Person Maybe" is a person with missing information.
- Other functors can be easily defined (and then composed) to represent things such as Mandatory/Optional, Valid/Invalid, etc.
I saw in the presentation submitted in another post that a similar thing has been done in Vinyl. But this won't work so well, because in the "rigid" type some fields are still supposed to remain wrapped in Maybe.
That’s not necessary a problem. If you add a field: ,favoriteNumber :: f (Maybe Int) Then, in Person Maybe, a value of Nothing in favoriteNumber would mean “not entered” while Just Nothing would be “none”. Maybe you have some specific problem in mind?

On 13.08.2014 00:26, Daniel Gorín wrote:
On 12 Aug 2014, at 20:23, Wojciech Narczyński
wrote: W dniu 2014-08-12 15:01, Daniel Gorín pisze:
On 11 Aug 2014, at 23:16, Wojtek Narczyński
wrote: If you declare Person class in Java, you automatically get a thingy that you can readily use in UI construction, because all the fields can temporarily be null, even the required ones. In Haskell you'd need two data types: the usual proper Haskell data type, and another which wraps every field in Maybe, facilitates editing, validation, etc. Perhaps it would be possible to generate one data type from the other, or generate both from a common specification. At least this part you can achieve rather easily by parametrizing each field in your record by a functor. E.g.:
data Person f = Person { firstName :: f String ,lastName :: f String ,birthDate :: f Date ,height :: f Int }
Then you get:
- "Person Id" is a person with every field set in stone.
- "Person Maybe" is a person with missing information.
- Other functors can be easily defined (and then composed) to represent things such as Mandatory/Optional, Valid/Invalid, etc.
I saw in the presentation submitted in another post that a similar thing has been done in Vinyl. But this won't work so well, because in the "rigid" type some fields are still supposed to remain wrapped in Maybe. That’s not necessary a problem. If you add a field:
,favoriteNumber :: f (Maybe Int)
Then, in Person Maybe, a value of Nothing in favoriteNumber would mean “not entered” while Just Nothing would be “none”. Maybe you have some specific problem in mind?
There is such a distinction in certain DBMSes: null vs "". It is confusing even to developers, not to mention users.

On Tue, Aug 12, 2014 at 09:23:35PM +0200, Wojciech Narczyński wrote:
W dniu 2014-08-12 15:01, Daniel Gorín pisze:
On 11 Aug 2014, at 23:16, Wojtek Narczyński
wrote: If you declare Person class in Java, you automatically get a thingy that you can readily use in UI construction, because all the fields can temporarily be null, even the required ones. In Haskell you'd need two data types: the usual proper Haskell data type, and another which wraps every field in Maybe, facilitates editing, validation, etc. Perhaps it would be possible to generate one data type from the other, or generate both from a common specification. At least this part you can achieve rather easily by parametrizing each field in your record by a functor. E.g.:
data Person f = Person { firstName :: f String ,lastName :: f String ,birthDate :: f Date ,height :: f Int }
Then you get:
- "Person Id" is a person with every field set in stone.
- "Person Maybe" is a person with missing information.
- Other functors can be easily defined (and then composed) to represent things such as Mandatory/Optional, Valid/Invalid, etc.
I saw in the presentation submitted in another post that a similar thing has been done in Vinyl. But this won't work so well, because in the "rigid" type some fields are still supposed to remain wrapped in Maybe.
Then make the Person type completely freely polymorphic data Person f l b h = Person { firstName :: f , lastName :: l , birthDate :: b , height :: h } I do this a lot, and with suitible type synonyms is really a nice way of working (especially with lenses). Tom
participants (18)
-
Alberto G. Corona
-
Alexander Vieth
-
Alois Cochard
-
Brandon Allbery
-
Chris Warburton
-
Daniel Gorín
-
Heinrich Apfelmus
-
Jim Stuttard
-
John Lato
-
ok@cs.otago.ac.nz
-
Raphaël Mongeau
-
Rik van der Kleij
-
Steve Schafer
-
Tikhon Jelvis
-
Tom Ellis
-
Tom Nielsen
-
Wojciech Narczyński
-
Wojtek Narczyński