pietervdvn / Lang

Yet another programming language
1 stars 1 forks source link

Automatic Lensing #11

Open RianGoossens opened 10 years ago

RianGoossens commented 10 years ago

Automatically add lensing to records.

(Haskell syntax)

Suppose we have a record

data Game = {
    score :: Int,
    player :: Entity
    entities :: [Entity]
}

with Entity:

data Entity = {
    name :: String
    position :: Point
}

and Point:

data Point = {
    x :: Int,
    y :: Int
}

Each record would get automatic lensing. If you want the player entity to go up, you could write:

let game2 = game.player.position.y `modify` (+1)

or

(+=) = flip modify (+)
let game2 = game.player.position.y += 1

To do something for each element in a list, forEach would be a solution:

let game2 = game.entities `forEach` y *= 2

In some cases modify could be left out with automatic function renaming:

let game2 = game.score `modify` (\x -> function x 3)
--equivalent to
let game2 = game.score `function=` 3
let game2 = game.score `modify` double
--equivalent to
let game2 = game.score double!

Maybe operations could be chained together with do by providing a correct Monad instance:

let game2 = do
    game.player.position.y += 1
    game.player.position.x -= 3
    game.entities `update=` game
pietervdvn commented 10 years ago

Reading values

Lot's of these things can be easily constructed using type directed function resolution on the .-operator.

so, let

# Infix (.) 5 rightmost
(.)     : a -> (a -> b) -> b
a f    = f a

Which enables expressions like

game.player.position.y

For these, the accessors are automatically generated as

position    : Entity -> Point
position (Entity _ p)   = p
player       : Game -> Entity
....

Modifying values

Of course, we want to be able to modify these values, with an expression as

game.player.position.setX 10

This would be parsed as

game . (player . (position . (setX 10) ) )

setX 10 has a type Point -> Point. Let position have an alternate declaration as:

position    : (Point -> Point) -> Entitiy -> Entity
position (Entity name point) f  = Entity name (f point)

This means that the expression .setX 5 has the type Point -> Point, the expression .point.setX 5 has the type Entity -> Entity, allowing chaining. Note that the point is here the modifying version.

Remarks

Increasing a value with one could be done with

game.entity.point.x (+1)

For a list, no special methods are needed. . acts as application. This means you could write expressions as

[1,2,3].map (+1)

A monad instance could be easily provided with the State-monad, which provides a modify function:

modify    : (a -> a) -> State a
modify f  = do    a  <- get
                          put $ f a

Then, expressions could be written as

doStuff    : State Game
doStuff    = do    modify ( .player.position.y (+1) )
                        modify ( . player.position.x (-3) )
                        modify ( .entities.map update)

Conclusion

There is minimal support needed for this feature:

pietervdvn commented 10 years ago