Defines Zipper and Grid. Both comonads yada yada
This commit is contained in:
commit
a71928382b
5 changed files with 310 additions and 0 deletions
62
Grid.elm
Normal file
62
Grid.elm
Normal file
|
@ -0,0 +1,62 @@
|
|||
module Grid exposing (..)
|
||||
|
||||
import RingList exposing (..)
|
||||
|
||||
type alias Grid a = RingList (RingList a)
|
||||
|
||||
{- Basic conversion -}
|
||||
generate : Int -> Int -> (Int -> Int -> a) -> Grid a
|
||||
generate width height gen = let
|
||||
row = RingList.fromList 1 [2..width]
|
||||
cols = RingList.fromList 1 [2..height]
|
||||
grid = RingList.map (\y -> RingList.map (\x -> (x, y)) row) cols
|
||||
in map (uncurry gen) grid
|
||||
|
||||
toList : Grid a -> List (List a)
|
||||
toList grid = RingList.toList <| RingList.map RingList.toList <| grid
|
||||
|
||||
{- Functor like functions -}
|
||||
map : (a -> b) -> Grid a -> Grid b
|
||||
map f grid = RingList.map (RingList.map f) grid
|
||||
|
||||
edit : (a -> a) -> Grid a -> Grid a
|
||||
edit f grid = RingList.edit (RingList.edit f) grid
|
||||
|
||||
{- Comonad functions -}
|
||||
extract : Grid a -> a
|
||||
extract grid = grid.focus.focus
|
||||
|
||||
-- It was quite difficult to define duplicate. A simple RL.map RL.dup >> RL.dup
|
||||
-- is not the right definition (this would be too simple). With the transpose
|
||||
-- trick it is quite ok to reason about (draw the diagrams yourself!)
|
||||
duplicate : Grid a -> Grid (Grid a)
|
||||
duplicate grid = grid |> RingList.map RingList.duplicate |> transpose |> RingList.map RingList.duplicate |> transpose
|
||||
|
||||
extend : (Grid a -> b) -> Grid a -> Grid b
|
||||
extend f w = map f (duplicate w)
|
||||
|
||||
(=>>) : Grid a -> (Grid a -> b) -> Grid b
|
||||
(=>>) = flip extend
|
||||
|
||||
{- Domain functions -}
|
||||
shiftLeft : Grid a -> Grid a
|
||||
shiftLeft grid = RingList.map RingList.shiftLeft grid
|
||||
|
||||
shiftRight : Grid a -> Grid a
|
||||
shiftRight grid = RingList.map RingList.shiftRight grid
|
||||
|
||||
shiftUp : Grid a -> Grid a
|
||||
shiftUp grid = RingList.shiftLeft grid
|
||||
|
||||
shiftDown : Grid a -> Grid a
|
||||
shiftDown grid = RingList.shiftRight grid
|
||||
|
||||
transpose : Grid a -> Grid a
|
||||
transpose grid = let
|
||||
newBefore grid = List.map RingList.extract grid.before
|
||||
newAfter grid = List.map RingList.extract grid.after
|
||||
newFocus rl = RingList (newBefore rl) (extract rl) (newAfter rl)
|
||||
nb = List.map newFocus <| RingList.iterate1N (List.length grid.focus.before) shiftRight grid
|
||||
nf = newFocus grid
|
||||
na = List.map newFocus <| RingList.iterate1N (List.length grid.focus.after) shiftLeft grid
|
||||
in RingList nb nf na
|
67
Main.elm
Normal file
67
Main.elm
Normal file
|
@ -0,0 +1,67 @@
|
|||
import Grid exposing (..)
|
||||
import RingList exposing (..)
|
||||
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.App as App
|
||||
import Html.Events exposing (..)
|
||||
import Random
|
||||
import Color exposing (..)
|
||||
import Time exposing (Time, second)
|
||||
|
||||
|
||||
main =
|
||||
App.program
|
||||
{ init = init
|
||||
, view = view
|
||||
, update = update
|
||||
, subscriptions = subscriptions
|
||||
}
|
||||
|
||||
width = 21
|
||||
height = 16
|
||||
|
||||
-- MODEL
|
||||
|
||||
type alias World = Grid (Int, Float)
|
||||
type alias Model =
|
||||
{ grid : World
|
||||
, history : List (Int, Float)
|
||||
}
|
||||
|
||||
init : (Model, Cmd Msg)
|
||||
init = (Model (Grid.generate width height (\x y -> (x, toFloat y))) [], Cmd.none)
|
||||
|
||||
|
||||
-- UPDATE
|
||||
|
||||
type Msg
|
||||
= Update World
|
||||
|
||||
succ (n, m) = (n + 1, m * 2)
|
||||
|
||||
update : Msg -> Model -> (Model, Cmd Msg)
|
||||
update msg model =
|
||||
case msg of
|
||||
Update grid -> (Model grid (Grid.extract grid :: model.history), Cmd.none)
|
||||
|
||||
|
||||
-- SUBSCRIPTIONS
|
||||
|
||||
subscriptions : Model -> Sub Msg
|
||||
subscriptions model = Sub.none
|
||||
|
||||
|
||||
-- VIEW
|
||||
|
||||
butt : World -> Html Msg
|
||||
--butt rl = button [ onClick (Update (RingList.edit succ rl)) ] [ RingList.extract rl |> toString |> text ]
|
||||
butt grid = button [ onClick (Update (Grid.edit succ grid)) ] [ Grid.extract grid |> toString |> text ]
|
||||
|
||||
view : Model -> Html Msg
|
||||
view model = let
|
||||
dupmodel = Grid.duplicate model.grid
|
||||
butts = Grid.map butt dupmodel
|
||||
listm = Grid.toList butts
|
||||
viewm = List.map (\row -> div [] (br [] [] :: row)) listm
|
||||
in div [] <| viewm ++ [div [] [model.history |> toString |> text]]
|
108
RandomAutomata.elm
Normal file
108
RandomAutomata.elm
Normal file
|
@ -0,0 +1,108 @@
|
|||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.App as App
|
||||
import Html.Events exposing (..)
|
||||
import Random
|
||||
import Color exposing (..)
|
||||
import Time exposing (Time, second)
|
||||
|
||||
|
||||
main =
|
||||
App.program
|
||||
{ init = (init size)
|
||||
, view = view
|
||||
, update = update
|
||||
, subscriptions = subscriptions
|
||||
}
|
||||
|
||||
size = 36
|
||||
|
||||
-- MODEL
|
||||
|
||||
type alias State = Maybe Int
|
||||
type alias Automaton = List (Int, Int)
|
||||
|
||||
type alias Model =
|
||||
{ states : List State
|
||||
, system : Automaton
|
||||
}
|
||||
|
||||
|
||||
init : Int -> (Model, Cmd Msg)
|
||||
init n = (Model (List.map Just [1 .. size]) [], Random.generate Update (genAut n))
|
||||
|
||||
|
||||
|
||||
-- UPDATE
|
||||
|
||||
type Msg
|
||||
= Step
|
||||
| Regen
|
||||
| Update Automaton
|
||||
| Sort
|
||||
|
||||
zip = List.map2 (,)
|
||||
|
||||
genAut : Int -> Random.Generator Automaton
|
||||
genAut n = Random.map (zip [1 .. n]) (Random.list n <| Random.int 1 n)
|
||||
|
||||
step : Automaton -> State -> State
|
||||
step ls s0 = case s0 of
|
||||
Nothing -> Nothing
|
||||
Just s -> List.filter (\(a,b) -> a == s) ls |> List.head |> Maybe.map snd
|
||||
|
||||
cmp l r = case (l, r) of
|
||||
(Nothing, Nothing) -> EQ
|
||||
(Nothing, Just n) -> LT
|
||||
(Just n, Nothing) -> GT
|
||||
(Just n, Just m) -> compare n m
|
||||
|
||||
update : Msg -> Model -> (Model, Cmd Msg)
|
||||
update msg model =
|
||||
case msg of
|
||||
Step -> (Model (List.map (step model.system) model.states) model.system, Cmd.none)
|
||||
|
||||
Regen ->
|
||||
init size
|
||||
|
||||
Update newAut ->
|
||||
(Model model.states newAut, Cmd.none)
|
||||
|
||||
Sort ->
|
||||
(Model (List.sortWith cmp model.states) model.system, Cmd.none)
|
||||
|
||||
|
||||
-- SUBSCRIPTIONS
|
||||
|
||||
subscriptions : Model -> Sub Msg
|
||||
subscriptions model =
|
||||
Time.every (0.1 * second) (\a -> Step)
|
||||
|
||||
|
||||
|
||||
-- VIEW
|
||||
|
||||
(=>) = (,)
|
||||
|
||||
state2Color : State -> Color
|
||||
state2Color s = case s of
|
||||
Nothing -> Color.black
|
||||
Just n -> hsl (degrees (toFloat n)*77) 1.0 (0.8 - 0.6 * (toFloat n)/size)
|
||||
|
||||
color2String : Color -> String
|
||||
color2String c = let rgb = toRgb c in "rgb(" ++ toString rgb.red ++ ", " ++ toString rgb.green ++ ", " ++ toString rgb.blue ++ ")"
|
||||
|
||||
block : Color -> Html msg
|
||||
block c = div [style ["background-color" => color2String c, "width" => "100px", "height" => "100px", "display" => "inline-block"]] []
|
||||
|
||||
view : Model -> Html Msg
|
||||
view model =
|
||||
div []
|
||||
( button [ onClick Regen ] [ text "Regenerate" ]
|
||||
:: button [ onClick Sort ] [ text "Sort" ]
|
||||
:: br [] []
|
||||
:: List.map (block << state2Color) model.states
|
||||
)
|
||||
|
||||
|
||||
|
58
RingList.elm
Normal file
58
RingList.elm
Normal file
|
@ -0,0 +1,58 @@
|
|||
module RingList exposing (..)
|
||||
|
||||
type alias RingList a =
|
||||
{ before : List a
|
||||
, focus : a
|
||||
, after : List a
|
||||
}
|
||||
|
||||
{- Basic conversion -}
|
||||
fromList : a -> List a -> RingList a
|
||||
fromList a l = RingList [] a l
|
||||
|
||||
toList : RingList a -> List a
|
||||
toList rl = List.reverse rl.before ++ [rl.focus] ++ rl.after
|
||||
|
||||
{- Functor like things -}
|
||||
map : (a -> b) -> RingList a -> RingList b
|
||||
map f rl = RingList (List.map f rl.before) (f rl.focus) (List.map f rl.after)
|
||||
|
||||
edit : (a -> a) -> RingList a -> RingList a
|
||||
edit f rl = RingList rl.before (rl.focus |> f) rl.after
|
||||
|
||||
{- Comonad functions -}
|
||||
extract : RingList a -> a
|
||||
extract rl = rl.focus
|
||||
|
||||
duplicate : RingList a -> RingList (RingList a)
|
||||
duplicate rl = let
|
||||
lefts = iterate1N (List.length rl.before) shiftRight rl
|
||||
rights = iterate1N (List.length rl.after) shiftLeft rl
|
||||
in RingList lefts rl rights
|
||||
|
||||
extend : (RingList a -> b) -> RingList a -> RingList b
|
||||
extend f w = map f (duplicate w)
|
||||
|
||||
(=>>) : RingList a -> (RingList a -> b) -> RingList b
|
||||
(=>>) = flip extend
|
||||
|
||||
{- Domain functions -}
|
||||
shiftLeft : RingList a -> RingList a
|
||||
shiftLeft rl = case rl.after of
|
||||
[] -> case List.reverse rl.before of
|
||||
[] -> RingList [] rl.focus []
|
||||
x::xs -> RingList [rl.focus] x xs
|
||||
x::xs -> RingList (rl.focus :: rl.before) x xs
|
||||
|
||||
shiftRight : RingList a -> RingList a
|
||||
shiftRight rl = case rl.before of
|
||||
[] -> case List.reverse rl.after of
|
||||
[] -> RingList [] rl.focus []
|
||||
x::xs -> RingList xs x [rl.focus]
|
||||
x::xs -> RingList xs x (rl.focus :: rl.after)
|
||||
|
||||
{- From here we have private functions -}
|
||||
iterate1N : Int -> (a -> a) -> a -> List a
|
||||
iterate1N n f a = case n of
|
||||
0 -> []
|
||||
m -> f a :: List.map f (iterate1N (m - 1) f a)
|
15
elm-package.json
Normal file
15
elm-package.json
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"version": "1.0.0",
|
||||
"summary": "helpful summary of your project, less than 80 characters",
|
||||
"repository": "https://github.com/user/project.git",
|
||||
"license": "BSD3",
|
||||
"source-directories": [
|
||||
"."
|
||||
],
|
||||
"exposed-modules": [],
|
||||
"dependencies": {
|
||||
"elm-lang/core": "4.0.5 <= v < 5.0.0",
|
||||
"elm-lang/html": "1.1.0 <= v < 2.0.0"
|
||||
},
|
||||
"elm-version": "0.17.1 <= v < 0.18.0"
|
||||
}
|
Reference in a new issue