Creative Commons Licence This work is licensed under a Creative Commons
Attribution-ShareAlike 4.0 International License

Source: gitlab

Snake in Elm

Andy Balaam
artificialworlds.net/blog

Contents

Snake

Elm

No guesswork

No guesswork

  • Every piece of state is in the model
  • If it's not in the model, you can't see it
  • Every function is pure
  • State flows through the code, instead of living in it
  • Feels safe: no unexpected interactions
  • Haskell

    Or, "The Price You Pay"

    type alias Snake =
        {
              dir  : Direction
            , body : List Point
        }
    

    Haskell

    Or, "The Price You Pay"

    grow_snake : List Point -> List Point
    grow_snake body = body ++ repeat 5 ( Point 0 0 )
    

    Haskell

    eat_apple : Model -> Model
    eat_apple model =
        case List.head model.snake.body of
            Nothing -> model  -- Snake is empty - won't happen
            Just h  ->
                if h == model.apple
                   then
                       let ( apple_pos, seed ) =
                           new_apple_position model.random_seed world_size
                       in
                       {
                           model |
                               snake       <- grow_snake model.snake,
                               apple       <- apple_pos,
                               random_seed <- seed
                       }
                   else model
    
    

    Haskell

    view : Signal.Address Action -> Model -> Html
    

    HTML

    Make a DOM in code

    view address model =
        div
            [ class "main_div" ]
            [ text "Hello" ]
    

    <div class="main_div">Hello<div>
    

    HTML

    Including clever code

    game_trs : Model -> List Html
    game_trs model =
        List.map
            ( game_tr model )
            [1..model.size.height]
    

    Signals

    type Action = Tick Time | KeyPress KeyCode
    
    update : Action -> Model -> ( Model, Effects Action )
    update action model =
      case action of
        Tick now ->
          ( frame model now, Effects.tick Tick )
    
        KeyPress key ->
          ( process_key model key, Effects.none )
    

    Signals

    view : Signal.Address Action -> Model -> Html
    view address model =
        div
            [ onKeyDown address KeyPress ]
            [ game_table model ]
    

    More info

    Donate! patreon.com/andybalaam
    Play! Rabbit Escape
    Videos youtube.com/user/ajbalaam
    Twitter @andybalaam
    Blog artificialworlds.net/blog
    Projects artificialworlds.net