https://github.com/sjorn3/elm-fields
First class field names in elm, implemented using lenses.
https://github.com/sjorn3/elm-fields
lens records
Last synced: 8 months ago
JSON representation
First class field names in elm, implemented using lenses.
- Host: GitHub
- URL: https://github.com/sjorn3/elm-fields
- Owner: sjorn3
- License: bsd-3-clause
- Archived: true
- Created: 2017-07-13T00:03:14.000Z (about 8 years ago)
- Default Branch: master
- Last Pushed: 2021-09-13T18:47:07.000Z (about 4 years ago)
- Last Synced: 2025-02-12T13:27:42.525Z (8 months ago)
- Topics: lens, records
- Language: Elm
- Size: 16.6 KB
- Stars: 7
- Watchers: 3
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# elm-fields: First Class Fieldnames [](https://travis-ci.com/sjorn3/elm-fields)
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
```elm
import FieldLens exposing (..)
```Let's start by defining some simple player types for a potential game.
```elm
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.
```elm
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.```elm
{-
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 passingHere are a couple of slightly more complex examples of functions which take
a field and access it.```elm
{-
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
```