Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Locked thread
fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

For anyone looking to learn functional programming I wouldn't hesitate to consider Elm. It's very similar to a strictly evaluated, simplified, streamlined Haskell. Unlike many of the other FP languages, it retains the complete purity of Haskell, but it doesn't get bogged down in category theory. And it's a compile-to-js UI language so it's easy to get started (you don't even need to download anything for a while if you don't want to) and you get instant visual feedback. It also has first class support for its own unique take on Functional Reactive Programming, which is a very interesting take on managing interactions and state, sort of like an abstraction on top of callbacks.

I can write a lot more about Elm if anyone's interested.

Adbot
ADBOT LOVES YOU

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

VikingofRock posted:

Please do, I'd love to add it to the OP.



Elm is a pure, strictly evaluated functional language descended from Haskell, with bits and pieces taken from other ML-family languages like F#. It's unique in that it's not a general purpose programming language like the others mentioned in this thread, but rather it's a browser-based, Functional Reactive Programming UI language. There are other FRP implementations, but Elm is the only language I know of dedicated to the concept rather than being a library.

What is Functional Reactive Programming?

Functional Reactive Programming, or FRP, is a relatively new approach to building UI and animation (among other things). It abstracts events and callbacks into first-class, time-varying values that Elm calls Signals. In Elm, you define your program as pure functions that transform inputs to outputs, and then map input Signals over these functions. As a basic "Hello World" type example, the following function takes an (Int, Int) tuple and returns an Element (which just means "something that can be drawn to the screen"):
code:
render : (Int, Int) -> Element
render (x, y) = Graphics.Element.show (x, y)
We can then map the current position of the mouse onto this render function without our render function to produce a Signal Element, which means a time-varying object that is drawn to screen:
code:
-- Mouse.position is a built-in input Signal in Elm of type "Signal (Int, Int)"
main : Signal Element
main = Signal.map render Mouse.position
This program will always show the current mouse position, because as the mouse is moved, the input Signal "Mouse.position" is automatically updated, and the values flow through each function, updating their values in turn.

Every input to your program is handled in the same way, and complex behavior is defined as compositions of these basic building blocks. This paradigm naturally leads to a specific architectural pattern we call The Elm Architecture that ends up looking like this:
code:
-- MODEL (Where you define the data structures that will be used to represent your program's state)

type alias Model = { ... }


-- UPDATE (Where you define the possible actions, map input Signals to these actions, 
--         and write one or more state machines that define how your program state updates on each action)

type Action = Reset | ...

update : Action -> Model -> Model
update action model =
  case action of
    Reset -> ...
    ...


-- VIEW (Where you define how to visually display your program model. 
--       In Elm, you don't define visual transitions as such, rather 
--       you define what the entire output should look like given any possible model)

-- view can also be Model -> Element
view : Model -> Html 
view =
  ...
These sections can be composed together from smaller subsections that live in different modules, with each piece being pure and stateless. At the very end, you tie everything together by mapping input Signals onto the update function. It leads to a very clean style of code that is easy to reason about and test, and the guarantees of the language allow some cool things like the time traveling debugger and the near-total elimination of runtime exceptions.

There's a lot of other stuff to like about Elm. It has a helpful, growing community, an emphasis on making functional programming concepts approachable and easy to learn, a package manager that enforces semantic versioning, a virtual-dom rendering backend that's really fast, real-time modification of currently running code, a simple and powerful FFI, and more.

The best places to learn more are the official website and the mailing list.

fart simpson fucked around with this message at 16:09 on May 3, 2015

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

Malcolm XML posted:

a monad is a monoid in the category of endofunctors

This is the best way I've ever seen this explained. You don't even need to know anything about anything, just read it as unknown symbols and you can see what that quote is getting at:

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

HappyHippo posted:

Just a note about Elm, I've found this set of tutorials, Elm By Example and I wished I'd started here.

I like the idea behind Elm so far, but it's in version 0.15 and it shows. A lot of rough around the edges stuff. I'm going to stick with it though.

Yeah, I wouldn't use Elm for anything that "matters" yet. It's still pretty young and rapidly changing, with a major, compatibility breaking release about once every 3 months. But the core concept doesn't change, and that's what I really like about it.

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

As for when you'd actually use the monad instance for (-> r), the idea is you can have a single value that's implicitly passed to many different functions. What you'd actually use if you want this idea is the Reader monad.

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

Yes.

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

xtal posted:

I don't know if any other functional programmers run into this problem, but I have a really hard time deciding which language I want to use for new projects. My two main choices are Racket and Haskell. I think that Racket programs can be developed much faster because of the minimal syntax, dynamic typing and macro system. But they're less safe than Haskell programs, which have static typing and pure functions.

Are there any languages that are a compromise between the two, like a statically-typed, purely functional Lisp language? I'm trying to get into Typed Racket and I figure I could use the monad library for side effects. The benefit I see is that I can start with an untyped program and add types as needed.

Maybe it's because I've hardly used Racket, but I certainly don't find that programming in dynamically typed languages is faster.

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

Use cabal sandboxes for all your projects imo.

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

It basically is designed to be harder to learn than most other programming languages, at least assuming you already know a "normal" programming language. If you know Java and you want to learn C#, you're mostly just going "OK, this is how I do ____ in C#", but with Haskell, you have to learn to approach things from a different direction.

e: the guy above me said it better.

fart simpson fucked around with this message at 07:04 on Jun 19, 2015

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

I don't know exactly what your error message is, but in Haskell, variables have to start with a lowercase letter. If it starts with an uppercase letter, it's a type, so I'm guessing the compiler is complaining the T, Tc, Pc, etc types are not in scope. Try lowercasing them.

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

Oh yeah sorry, I felt like there was something wrong with my description.

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

VikingofRock posted:

I had never seen that operator before, but after sitting down with a pen and paper and figuring out what it does, that's really useful! I'll have to remember that.

You're the problem.

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

QuantumNinja posted:

Question about Elm: how would I go about making an Elm application interact with a database backend? The 'easiest' way I can imagine from the API is to use JSON to post requests to some server-side script and get the results back. Is there an approach (maybe as a library or tutorial) that doesn't require doing something like that for user login authentication?

I'd probably look at the Firebase bindings linked above. Even if you don't use it, you can look at that for ideas on how you'd generally do something like this. This is really something that you'd want to implement with the relatively new Task system in Elm, but I think you could also do something with http or websockets to communicate with a backend. It might not be that hard to write bindings for an existing Javascript library that can do what you want, either.

There aren't really many libraries for something like this at this point.

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

Embedded stuff?

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

Snak posted:

Wait really? I should just make a statement for each possible value of Day? I thought that sounded like poor solution that does not scale well...

Well, think about what you need to write. This is what you need:
code:
show :: Day -> String
There's a way to do it with a list like you were trying to, but what you've actually written is a Show implementation for Day like this:
code:
show :: Int -> String
In a simple case like this, it's simpler to just match on each possible Day instead of involving enumeration of lists.

fart simpson fucked around with this message at 01:19 on Sep 17, 2015

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

Well, there is a way to do it. I'd involve another typeclass, called Enum: https://hackage.haskell.org/package/base-4.8.1.0/docs/Prelude.html#t:Enum

You would want to define an instance of Enum for your Day type. Or you could derive the instance in this case, but I don't know if you know deriving yet?

e: Since you already have it working, I'll show you a way of doing it more along the lines of how you originally approached the problem:
code:
data Day = Mon | Tue | Wed | Thu | Fri | Sat | Sun deriving (Enum)

instance Show Day where
	show day = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"] !! fromEnum day 
In a simple case like this, I'd prefer to just hardcode in the pattern matches rather than involving Enum though.

fart simpson fucked around with this message at 01:32 on Sep 17, 2015

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

Oh yeah there's that too.

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

GrumpyDoctor posted:

There's no way around hardcoding an explicit mapping for each Enum value somewhere.

But maybe you can trick the compiler into doing it for you!

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

The creator of Elm just did a talk sort of about the benefit of immutability that I found pretty interesting:
https://www.youtube.com/watch?v=DfLvDFxcAIA

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

Elm 0.16 was just released. There's a blog post about it: http://elm-lang.org/blog/compilers-as-assistants

The key feature is really the improved compiler error messages. I mean look at these, these are nice:




There's also some improved speed in the generated JS, and TCE, etc who cares

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

A guy did a good talk at Strange Loop that I just watched where he gives a really high level description of what it's like to actually use Elm. I liked the talk:
https://www.youtube.com/watch?v=FV0DXNB94NE

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

I just took a trip down Elm memory lane. I've been messing around in Elm for over 2 and a half years now, and I just went back and updated one of my first projects that's still around on github with the bare minimum in updates so it will actually compile with the latest Elm version. It's kind of crazy how much Elm has grown in that time. Back then, everything was unorganized and nobody knew what they were doing or what coding style to use, so we were all 100% making it up as we went along.

I was probably one of the only people that's used the experimental Automaton library, which is based on Arrowized Functional Reactive Programming. I used it to implement a kind of lazy rendering system that would do a cheap, quick state diff and only re-render different pieces of the UI if their relevant state had changed, then it would cache the output for the next tick. This is what it looked like:
code:
module Rendertron where

import Signal
import String

import Model
import Interface
import SpecialEffects

import Automaton (..)
import Automaton

type Rendertron = Automaton Model.State Element
type HiddenState a = {input : a, render : a -> Element, output : Element}

rendertron : (Model.State -> a) -> (a -> Element) -> Model.State -> Rendertron
rendertron getter renderer state =
    let a = getter state
        state' = HiddenState a renderer <| renderer a
        step i s =  let a = getter i
                    in  if a == s.input
                        then (s, s.output)
                        else let o = renderer a
                             in  ({s| input <- a, output <- o}, o)
    in  hiddenState state' step

renderer : [Rendertron] -> Automaton Model.State [Element]
renderer rendertrons = Automaton.combine rendertrons

renderLines : Automaton Model.State [Element] -> Signal Model.State -> Signal Element
renderLines renderer state = flow down <~ run renderer [] state

renderGame : Int -> Automaton Model.State [Element] -> Signal Model.State -> Signal (Int, Int) -> Signal Element
renderGame seed renderer state dimensions =
    let instructions = constant Interface.instructions
        seed' = (\(w, h) -> container w h bottomLeft (plainText <| "random seed: " ++ show seed)) <~ dimensions
        elements = run renderer [spacer 0 0] state
        messages = (\elems (w, h) -> container w h (midTopAt (relative 0.5) (relative 0.7)) <| head elems) <~ elements ~ dimensions
        lines    = (\elems (w, h) -> container w h middle <| flow down (tail elems)) <~ elements ~ dimensions
        distorted = (\(w, h) state messages gameScreen -> layers [messages, gameScreen]) <~ dimensions ~ state ~ messages ~ lines
    in  layers <~ (Signal.combine [instructions, distorted, seed'])

-- Program specific:

lines : Model.State -> [Rendertron]
lines initialState =
    [ rendertron (\state -> state.messages)
        (\messages -> flow down <| map (plainText . .msg) messages)
        initialState
    , rendertron (\state -> ())
        (\_ -> flow right [Interface.chugButton, plainText " time acceleration: ", flow right Interface.timeAccelerationButtons])
        initialState
    , rendertron (\state -> (state.person.weight, state.person.orientation, state.person.gender, state.person.sex, state.person.alcoholism))
        (\(weight, orientation, gender, sex, alcoholism) -> flow right [ plainText "you are a "
                                                                       , plainText . String.left 5 . show <| weight, plainText "kg "
                                                                       , plainText . String.toLower . show <| orientation
                                                                       , plainText <| " " ++ showGender gender sex
                                                                       , plainText . showAlcoholism <| alcoholism
                                                                       ]
        )
        initialState
    , rendertron (\state -> .name (snd state.person.beers))
        (\name -> flow right [plainText "your current beer of choice is ", plainText . show <| name])
        initialState
    , rendertron (\state -> fst <| state.person.beers)
        (\beer -> flow right [plainText "of which you have ", width 35 <| plainText . show <| beer, plainText " ml left in the glass"])
        initialState
    , rendertron (\state -> state.person.alc)
        (\alc -> flow right [plainText "you got ", plainText . String.left 4 . show <| alc, plainText " grams of unabsorbed ethanol in ur belly"])
        initialState
    , rendertron (\state -> state.person.bac)
        (\bac -> flow right [plainText "ur bac is: ", plainText . String.left 6 . show <| bac])
        initialState
    , rendertron (\state -> (state.person.urine, state.person.wetSelf, state.person.urinating))
        (\(urine, wetSelf, urinating) -> plainText <| Interface.peeDisplay urine wetSelf ++ (if urinating then " (you are peeing)" else ""))
        initialState
    , rendertron (\state -> state.drinks)
        (\drinks -> flow right [plainText "you've had ", plainText . String.left 4 . show <| drinks, plainText " beers"])
        initialState
    ,  rendertron (\state -> Interface.timeDisplay state.elapsed)
        (\elapsed -> flow right [plainText "u been at the bar for: ", plainText elapsed])
        initialState
    ,  rendertron (\state -> ())
        (\_ -> flow right [Interface.sipButton, Interface.gulpButton, Interface.urinateButton])
        initialState
    ,  rendertron (\state -> ())
        (\_ -> flow right [Interface.orderButton, Interface.orderButton2])
        initialState
    , rendertron (\state -> (state.person.conscious, state.person.alive))
        (\(conscious, alive) -> if | not alive -> centered . Text.height 30 . bold . toText <| "you are dead. rip"
                                   | not conscious -> centered . Text.height 30 . bold . toText <| "you've passed out"
                                   | otherwise -> spacer 0 0
        )
        initialState
    ]

showGender : Model.Gender -> Model.Sex -> String
showGender gender sex =
    case sex of
        Model.Male   -> if gender == Model.Cis then "cisman" else "transwoman"
        Model.Female -> if gender == Model.Cis then "ciswoman" else "transman"


showAlcoholism : Float -> String
showAlcoholism a = if | a < 0.25  -> " who never drinks"
                      | a < 1     -> " social drinker"
                      | a < 1.5   -> " heavy drinker"
                      | a < 2     -> " functioning alcoholic"
                      | otherwise -> " alcoholic"
But now everyone uses a totally different UI library called elm-html which has lazy rendering built in, and everything's much more standardized around a common app architecture. We have a style guide, a gofmt style utility called elm-format, and it's just very different. Here's a simple website I've started working on recently:
code:
module Main where

import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (..)
import Graphics.Element exposing (..)
import Color

import StartApp.Simple as StartApp


main =
  StartApp.start { model = model, view = view, update = update }



port title : String
port title =
  "Title"


model = 
  False


update action model =
  case action of
    _ -> not model


view address model =
  div 
    [ style 
      [ ("fontFamily", "\"Raleway\", sans-serif") 
      , ("color", "black")
      , ("position", "relative")
      ] 
    ] 
    [ hamburger address model
    , fullscreenMenu address model
    , logo
    , body
    , footer
    , node "link"
      [ rel "stylesheet"
      , href "https://fonts.googleapis.com/css?family=Raleway:400,700,900,800"
      , type' "text/css"
      ]
      []
    ]


logo =
  div 
    [ style 
      [ ("cursor", "pointer") 
      , ("fontSize", "20px")
      , ("fontWeight", "800")
      , ("lineHeight", "80px")
      , ("width", "400px")
      , ("margin", "0px auto")
      ] 
    ] 
    [ text "GIGI"
    , spacer 150 1 |> color Color.lightGrey |> fromElement
    , node "link" 
      [ rel "stylesheet"
      , href "https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css"
      ]
      []
    ]
    

body =
  div 
    [ style 
      [ ("fontSize", "13px")
      , ("color", "#8D8D8D")
      , ("lineHeight", "22px")
      , ("letterSpacing", "1px")
      , ("width", "400px")
      , ("margin", "50px auto")
      ]
    ] 
    [ h1 
      [ style 
        [ ("fontSize", "43px")
        , ("fontWeight", "900")
        , ("lineHeight", "70px")
        , ("color", "black")
        , ("letterSpacing", "0px")
        ]
      ] 
      [ text "PROJECTS" ]
    , text "Please check my portfolio."
    , pic Color.grey
    , pic Color.lightGrey
    , pic Color.grey
    ]


hamburger address model =
  node
    "i"
    [ class <| if model then "fa fa-close" else "fa fa-bars"
    , style 
      [ ("backgroundColor", "black") 
      , ("position", "fixed")
      , ("right", "5%")
      , ("top", "30px")
      , ("padding", "20px")
      , ("color", "white")
      , ("fontSize", "18px")
      , ("cursor", "pointer")
      , ("zIndex", "9999")
      ]
    , onClick address ()
    ]
    []
    

fullscreenMenu address model =
  if model then
    div
      [ style
        [ ("position", "fixed")
        , ("height", "100%")
        , ("width", "100%")
        , ("background", "rgba(0, 0, 0, 0.95)")
        , ("zIndex", "9998")
        ]
      ]
      [ text "welp," ]
  else
    div [] []


footer =
  div
    [ style 
      [ ("height", "300px")
      , ("marginTop", "150px")
      , ("background", "#F1F1F1")
      , ("color", "#686868")
      , ("letterSpacing", "1px")
      , ("fontSize", "12px")
      , ("textAlign", "center")
      ]
    ]
    [ divSpacer 150
    , text "© Copyright 2015 deadfoxygrandpa.xyz. All Rights Reserved." 
    ]


pic c =
  p [] [ spacer 360 305 |> color c |> fromElement ]
  
  
divSpacer h =
  div
    [ style
      [ ("height", toString h ++ "px")
      , ("width", "100%")
      ]
    ]
    []
There was no real point to this post, it was just something that I thought was kind of fun to look back on.

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

For fun, that Automaton lazy renderer ended up being used for this: http://beer.deadfoxygrandpa.xyz. This was before Elm had the elm-html package, so all the graphics were done in a kind of weird but cool abstraction layer that didn't give you any access at all to normal HTML or CSS stuff.

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

I didn't check this thread in a while and hey look a lot of Elm related posts. I feel like replying to some of them, so here goes.

Maluco Marinero posted:

So I'm going through a phase of being ridiculously sold on Elm and wanting to try something non trivial in it. Seriously watch Evan's Lets be Mainstream talk, it's amazing to see a young language in the front end with responsible management, ensuring you can actually rely on packages, coding style, etc etc.

The foundation of the elm architecture is great too. I had one question though that maybe fart simpson could help me with. With the StartApp package it has a way to send in inputs and map them to actions for the model. Do components have any way to request Signals themselves, as I can see cases where you'd have say a Draggable component, and that'd like to listen to the Mouse.position signal once you start dragging, or a timer listening to (Time.every Time.millisecond).

All that said though, the animation example nearly gets there with Effects.tick. You're element is always going to know whether it needs to be reading from a signal, with a Draggable it would have a state of Dragging so it knows to trigger an effect at that point, so I guess all I'd be looking for is a way to make a Signal be polled by a Task that you can map into an effect. Does this seem reasonable? If it's at all possible to collect from a Signal with a task then you can keep the Static Signals, yet only be turning them into actions when actually required, keeping the possible complications down of polling say the Mouse position continuously.

I guess what I'm looking for is just something that can do (Signal a -> Task Never a) and then if be golden. Elm could do with a Hoogle-like.

I'm not quite sure I understand your third paragraph, but in general for a subcomponent that needs an input signal like Mouse.position I'd just hook it up to the input section of StartApp.start and pass it down the chain to the component(s) that need it. There's likely some way this can be made a little more friendly, like how a more recent package named elm-transit seems to have made it easier to do things like time based animations in nested modules.

I'm not sure what complications you mean about polling the Mouse position. If you're using elm-html with the lazy functions then it shouldn't really be a performance hit, if that's what you mean.

Sinestro posted:

I'm curious about people's experiences using Elm to develop a traditional website versus a 'web app', in terms of stuff like URLs and just general advice.

So actually I've mostly used Elm for little apps and games, and not much for websites, but in the past few weeks I've been starting to make a website for a friend. It's been going well so far, and the most frustrating, hardest part of it is dealing with CSS. I hate CSS, but if what you're using Elm for is writing the HTML and replacing the JavaScript parts, then I find it pretty pleasant. What I'm doing now is here if you'd like to see what it looks like, or you can look around the source of the official Elm websites https://github.com/elm-lang/elm-lang.org and https://github.com/elm-lang/package.elm-lang.org.

The language itself seems really nice to me for this type of thing. The not so nice parts are basically the small community. Sometimes there's a thing you want to do, but there's no binding for it in the core libraries and nobody's made a package to do it yet, so you have to do it on your own. Sometimes it's surprisingly trivial stuff, like I wanted to know how far down the page someone has scrolled so far. I basically had to do it myself by writing a native binding library to turn window.pageYOffset into an input signal. My only other option here would have been to use a port and set up an event listener in my html file and pass in the values.

It's constantly getting better, but don't write stuff in Elm expecting mature frameworks or anything. It's still very much a young, experimental language. It's possible to get stuff done in it, and I really like working in it though, so if you do end up writing stuff in it you can actually help out the community by giving feedback or publishing new packages or something.

Rudest Buddhist posted:

I tried using elm on a little scheduling pet project and could not find a decent way to get around basic routing. I think it really shines on fancy single page web apps.

Maluco Marinero posted:

By the looks of it it's just missing a decent package. Routing in web apps is pretty straightforward if you know how to go about it, with something that can map paths to a Route Type with parameters.

You'd need to write Native bindings to do it properly in Elm though, so you can bind to the various page change events.

Routing is something people have talked about for a while, and only recently has there seemed to be any solution at all to it. I like the looks of elm-transit-router the best so far, and I'm going to try using it in my current project. The author just announced it on the mailing list like a week ago, though.

There have been bindings to the history API for a while, so I think everything necessary is already bound and packaged. If you feel like working with the URLs directly instead of using one of the only two existing routing packages, look here.

Maluco Marinero posted:

From what I see he's not ignoring it, but trying to get away without it for as long as possible to avoid bloating the language. Feels reasonable, and there's nothing saying it won't ever get implemented. I think it's a good thing that every feature will have to earn its spot, although I agree that typeclasses are kinda important. When I tried doing a typeclass style approach in Scala ( having played a lot with Haskell beforehand ) I realised just how much of a boon a good implementation of typeclasses is for cutting down on boilerplate. Unfortunately trying it in Scala, while possible, just feels nothing like it.

Yeah. Evan has a long term view of this stuff. He thinks it's harder to take language features away once people have started using them than it is to add new language features, and he really wants to keep the core language small and simple. He's not opposed to typeclasses, and I've seen him say several times on the mailing list that he knows he will eventually add typeclasses or something similar, but he doesn't seem to love typeclasses that much and wants to make sure there's not a better solution out there. There was an alternate version of the compiler that supported F# style computation expressions and I think it was done with records rather than typeclasses.

A year ago people didn't know how to trigger a state update from an action on a child component and there were some different proposals on what to do about it. People were talking about changing the Signal graph structure to allow looping signals in certain situations, some people wanted monadic signals, and eventually they went with what became Tasks and the Elm Architecture, which I think turned out pretty well. Also, Evan just left his previous company and got hired by another company that's been really active in the Elm community. They use Elm in their website and product quite a bit, and are probably the collectively most experienced group out there at actually using Elm to make real stuff, so we're expecting some positive changes in how development on the language goes. Specifically there's been a lot of talk about involving more people other than just Evan in development of the compiler and core libraries, and standardizing on a new system for native JS bindings that will allow people to do more stuff that just isn't easy right now.

I guess my point is Elm is still changing rapidly and the creator is finding it difficult to keep up as he's been The Only Guy up to this point. There's good ideas out there but a hesitance to make significant changes without really evaluating them first. I think these things will get better, but in the meantime if you want more of a haskell in the browser experience check out PureScript, which I haven't used but a lot of people seem to like.

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

Maluco Marinero posted:

Im not concerned about the performance, more just good encapsulation. Generally when you mousedown on something Draggable you want to track the init position, and then poll mouse movements globally until mouseup. It'd be nice to encapsulate that as an effect that's just a task that gets the next notify call of a signal (and possibly combines signals if you needed to). That way the signals stay static, and the signal -> task can be mapped to actions specific to the component rather than being passed down from StartApp.

The real answer here is that this is type of thing is an ongoing discussion in the Elm community. There's people talking about wanting ore encapsulation like you describe, and there's other people talking about how they like how explicityly modeled everything is, and all that's really needed is something to reduce some of the boilerplate. I'm not sure what I think about all of it, but I kind of lean toward not thinking something like the Signal a -> Task Never a function would be a good thing. I find the more I work with the Elm Architecture and explicitly passing things down the hierarchy the more I appreciate how explicit everything is, and it makes stuff like more traditional components feel like a tricky implicitness. Like in your example, the Mouse position is an input that's needed to compute the full state of your program, isn't it?

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

Elm really does need a Hoogle though. I kind of want to write one, but I'm not sure I'm up to it at the moment.

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

QuantumNinja posted:

It's only okay if you do it in Elm, though.

Well yeah. There's a parser combinator library I'd probably use.

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

Maluco Marinero posted:

The problem with explicitly passing things down the hierarchy is that at a point you're preventing code reuse, because as per the architecture Actions are what get passed down, you could never write a nice module for Drag and Drop without boilerplate from outside to convert whatever the mouse input signal is to to the Drag and Drop's expected actions.

Maybe I just need to try another tack with this, but I just feel like it blocks off the kind of stuff I do with React components that can keep complex interaction code confined to the component in concern with a simple API that requires no internal knowledge.

What's wrong with something like "Signal.map DragAction Mouse.position"?

This discussion on the mailing list seems relevant to what you're talking about, as is this one.. I tend to agree with what Richard Feldman is saying in both of these threads.

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

Post some code? The answer is probably to Signal.map your input signals into an Increment action and merge them, then foldp the resulting action signal

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

Also, why not use StartApp like everyone else these days? Are you trying to dig into Signals and FRP to understand it better?

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

Try this, is it what you want? You basically just pass the mapped Increment action from the every second signal into the inputs field of the StartApp config
code:
type Action = Increment

ticker : Signal Action
ticker = Signal.map (always Increment) (Time.every Time.second)

type alias Game = { clicks : Int }

update : Action -> Game -> ( Game, Effects.Effects Action )
update action game =
    case action of
        Increment -> ( {game| clicks = game.clicks + 1 }, Effects.none )


view : Signal.Address Action -> Game -> Html
view address game = 
    div []
        [ img [ src "assets/cookie.jpeg", onClick address Increment ] []
        , div [] [text (toString game.clicks)]
        ]
        
app = 
    StartApp.start { init = (Game 0, Effects.none), update = update, view = view, inputs = [ticker] }
    
main = app.html

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

Fluue posted:

Perfect! I was about to post back with something similar (using input=[]). Is there a resource you have that explains why Effects.Effects needs to be used when dealing with this kind of signal? Is it because the ticker is constantly running?

Maluco Marinero is right, but StartApp.Simple doesn't have the inputs section that allows you to attach external Signals. The non-Simple StartApp has that, but it also requires you to specify Effects, even if those Effects are always none, like in my example.

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:


About a year and a half ago, I got an email from some UK book publisher asking if I would be interested in writing an Elm book.

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

Excuse me, but in War you can count your opponent's cards and secretly put your cards in a certain order when shuffling your winnings back in.

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

Yeah, I thought I knew functional programming pretty well until I started forcing myself to actually use Haskell for new hobby projects.

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

sarehu posted:

Monads are a generalization of the only sane API for constructing I/O actions in a "pure" functional manner -- and another associative law that makes sense.

Don't explain monads like this to someone who is skeptical about being able to understand them, thanks.

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

Well, Elm and Elixir serve different purposes. Elixir is for the server and Elm is for the client

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

xtal posted:

Does it still only run in browsers because building and learning a language just for front end web dev is straight up farcical

Like at least use blaze-react or whatever

JS is straight up farcical, you're right

Adbot
ADBOT LOVES YOU

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

That sounds kind of similar to how managed effects work in Elm and I assume also Haskell

  • Locked thread