
Generate semi-dynamic UIs with Haskell - pka
https://github.com/pkamenarsky/concur-static
======
dmitriid
I simply love it how every single Haskell framework I've seen that has "ease
of development" and "it's easy" and similar immediately devolves from this
(from Concur's docs [1]):

    
    
      hello = do
        button [onClick] [text "Say Hello"]
        text "Hello Sailor!"
    

into this:

    
    
      inputWidget = input [(Changed <<< unsafeTargetValue) <$> onChange, Focused <$ onFocus]
    

or this:

    
    
      inputWidget st = input [st {focusCount = st.focusCount+1} <$ onFocus
                             , ((\s -> st {currentText = s}) <<< unsafeTargetValue) <$> onChange]
    

for even the slightest modifications (which are not even complex in this case)

    
    
      These instances, allow a natural handling of 
      return values using <$>, <*>, <$, monadic 
      do-notation, etc
    

Right...

[1] [https://github.com/ajnsit/concur-
documentation/blob/master/R...](https://github.com/ajnsit/concur-
documentation/blob/master/README.md)

~~~
lalaithion
The second example can be rewritten as such:

    
    
        inputWidget = let
            changeAction = do
              v <- onChange
              return (Changed (unsafeTargetValue v))
            focusAction = do
              _ <- onFocus
              return Focused
          in input [changeAction, focusAction]
    

and likewise for the third:

    
    
        inputWidget st = let
            focusAction = do
              _ <- onFocus
              return (st {focusCount = st.focusCount+1})
            changeAction = do
              v <- onChange
              return (st {s = unsafeTargetValue v})
          in input [focusAction, changeAction]
    

(I didn't compile this, so hopefully there's no major mistakes here)

Believe it or not, many Haskell programmers prefer brevity when it comes to
programs like this. They're honestly not that unreadable once you learn the
meaning of a few infix operators.

~~~
dmitriid
I prefer the approach described here:
[http://www.haskellforall.com/2015/09/how-to-make-your-
haskel...](http://www.haskellforall.com/2015/09/how-to-make-your-haskell-code-
more.html)

------
ivanbakel
Cool application of Haskell's purity-by-default. I'm slightly surprised this
takes the approach of enumerating the whole input space to get all states,
though - given that termination for big spaces isn't a priority, why not just
explore all paths instead? Then you could return `Int` as much as you wanted,
if the actual code only goes through finitely many different values.

~~~
pka
> why not just explore all paths instead?

Author here.

The problem is that concur-static generates static JS code that encodes all
possible UI state transitions - so if the state space is big or infinite, so
will be the resulting generated JS.

I wanted to explore the viability of generating simple static UIs with _some_
level of dynamism. concur-static is definitely not intended as a replacement
for full-blown client side UI libraries/frameworks.

~~~
ivanbakel
> so if the state space is big or infinite, so will be the resulting generated
> JS.

I understand that, but it's not like this doesn't already choke on big input
spaces. Why not allow me to use a big input space with a small state space by
exploring the state space instead? Otherwise you just seem to be exploiting
the fact that small input spaces make for small state spaces, which seems like
an unnecessary indirection.

Or is it to try to enforce small state spaces to prevent programmer error?

~~~
pka
Ah, I understand now.

That seems like a good idea indeed, however I'm not sure how it'd look in
practice. The transition from input space to state space happens in the event
handlers, which currently look like this:

    
    
        onClick :: Bounded a => Enum a => a -> VDOM a
    

If I understand correctly, you're proposing something like:

    
    
        onClick :: Bounded a => Enum a => a -> VDOM b
    

Where b can be whatever (i.e. an Int, etc)? How would a be converted into b?

