Skip to content
This repository has been archived by the owner on May 18, 2024. It is now read-only.
/ elm-fields Public archive

First class field names in elm, implemented using lenses.

License

Notifications You must be signed in to change notification settings

sjorn3/elm-fields

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

23 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

elm-fields: First Class Fieldnames Build Status

This library provides a system for passing field names as arguments to functions and also applying updates to fields with a clean syntax.

Why use them?

  • Create functions which are general across the field that they make alterations to.
  • Easily readable syntax:
    • reset = set num_lives 10
    • addOne field = modify field ((+) 1)
    • addLife player = addOne num_lives player
  • Compose them with compose or composep to access and modify elements of deeply nested records with a smaller code size.
    • setX n = set (compose pos x) n
  • Although intended for records, the underlying lenses are general enough for any data type.

Game Example

import FieldLens exposing (..)

Let's start by defining some simple player types for a potential game.

type alias Player =
    { name : String, num_lives : Int, ammo : Int }


type alias Enemy =
    { name : String, num_lives : Int, ammo : Int }

We need to now define our lenses for the fields. They are defined in the form FieldLens get set, so all that needs to be defined is a getter and a setter.

The names are defined once and for all and are completely boilerplate, so let's define them right away and get it over with. Hopefully in the future this process will be completely automated.

name      = FieldLens .name      (\a r -> { r | name      = a })
num_lives = FieldLens .num_lives (\a r -> { r | num_lives = a })
ammo      = FieldLens .ammo      (\a r -> { r | ammo      = a })

Usage

Below is simply a list of examples of potential scenarios in the game and how they can be dealt with using first class fields.

{-
Imagine we have a list of enemies in play, and we want to find all of their
names, we can do this with a simple List.map.
-}
getEnemyNames : List Enemy -> List String
getEnemyNames =
    List.map (get name)


{-
The same function can be defined for players with only a change to the type.
In fact, you can define one getNames function for both enemies and players, or
any record that has the `name` field.

This is true for all of the functions in this example.
-}
getNames : List { b | name : a } -> List a
getNames =
    List.map (get name)


{-
However, this is not different to using `List.map .name`, so what can we
do that we couldn't already? You might want to reset all of the enemies ammo
to 20 at the start of a new round. 
-}
resetEnemies : List Enemy -> List Enemy
resetEnemies =
    List.map (set ammo 20)


{-
Let's say your player gets hit! We must reduce their number of lives,
which can be done with a call to `modify`
-}
playerHit : Player -> Player
playerHit =
    modify num_lives (\lives -> lives - 1)


{-
Or if you have a list of enemies and you just hit them all in one shot,
you might want to modify all of their lives in one go
-}
attackAllEnemies : List Enemy -> List Enemy
attackAllEnemies =
    List.map (modify num_lives (\lives -> lives - 1))

Field passing

Here are a couple of slightly more complex examples of functions which take a field and access it.

{-
If you're debugging and want to print some stats to the screen, you might
want to stringify one particular field, which is where using a field as an
argument comes in handy.
-}
toStringField : FieldLens a b c d -> a -> String
toStringField field = Debug.toString << get field

{-
You could also define a function which takes an `Int` field and turns it into
a `String` in a similar way using modify
-}
fieldToString : FieldLens a Int String d -> a -> d
fieldToString field = modify field String.fromInt

About

First class field names in elm, implemented using lenses.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 3

  •  
  •  
  •  

Languages