Lisplog

Blogging in Lisp

Search

Feed Aggregator

Rendered on Wed, 25 Apr 2018 06:33:25 GMT  newer latest older 
Next udpate: Wed, 25 Apr 2018 07:00:00 GMT feeds

A question about events and messages

via Elm Discourse - Latest posts by @aramiscd Aramís on Tue, 24 Apr 2018 20:13:11 GMT

That makes sense. Thanks for your reply!

Centralised list of past presentations

via Elm Discourse - Latest posts by @system system on Tue, 24 Apr 2018 19:41:16 GMT

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.

De-throning the List

via Elm Discourse - Latest posts by @robin.heggelund Robin Heggelund Hansen on Tue, 24 Apr 2018 17:11:48 GMT

While Sets doesn’t necessarily have to be ordered to be a set, Elm’s Set is. I’m working on a HashSet for Elm right now, so there could be multiple Set implementations in the future.

The point is that Set’s are collections, and so there are multiple functions available in the List and Array API that also makes sense to implement for Set.

Is it possible to capture type information about records?

via Elm Discourse - Latest posts by @miniBill Leonardo Taglialegne on Tue, 24 Apr 2018 16:33:33 GMT

I’m probably missing something, but:

type alias InceptionInner =
    { a : String
    , b : List Inception
    }


type Inception
    = Inception InceptionInner


inceptionMeta : Meta Inception
inceptionMeta =
    let
        unpack (Inception i) =
            i

        inner =
            object InceptionInner
                |> field "a" .a string
                |> field "b" .b (list <| lazy (\_ -> inceptionMeta))
                |> build
    in
    bimap
        (\e -> unpack >> e)
        (JD.map Inception)
        inner

not really pretty tbh

Strategies for representing persisted and un-persisted remote data

via Elm Discourse - Latest posts by @wmakley William Makley on Tue, 24 Apr 2018 16:28:40 GMT

So there is a lot to think about in this thread, but I thought I would respond to this at least:

My client-side UUID’s are only used for routing messages to the correct UI element. For example, if I have a list of elements, I generate a UUID for each one on page load simply by incrementing an Int, and any time a new item gets added, it gets a UUID that never changes.

The list itself is probably sorted either by some kind of implicit order, or a database column, but this is getting very off-topic from representing database records. My UUID’s are a UI implementation detail.

Is it possible to capture type information about records?

via Elm Discourse - Latest posts by @pdamoc Peter Damoc on Tue, 24 Apr 2018 15:50:00 GMT

This is progressing quite rapidly. I guess you could also write an example for a record containing a record.

Is it possible to capture type information about records?

via Elm Discourse - Latest posts by @miniBill Leonardo Taglialegne on Tue, 24 Apr 2018 15:38:12 GMT

I should probably publish this as a library. The API is not perfect but it’s reasonable, and it’s quite a compact way to define encoding and decoding.

I would really love some feedback.

Ellie: https://ellie-app.com/8hS7BwxpJa1/0

module Main exposing (main)

import Dict exposing (Dict)
import Html exposing (Html)
import Json.Decode as JD exposing (Decoder)
import Json.Encode as JE exposing (Value)
import Set exposing (Set)


type alias ObjectSimpleFields =
    { a : String
    , b : Int
    , c : List Float
    , d : MyList Bool
    }


type MyList a
    = Empty
    | Cons a (MyList a)


objectSimpleFieldsMeta : Meta ObjectSimpleFields
objectSimpleFieldsMeta =
    object ObjectSimpleFields
        |> field "a" .a string
        |> field "b" .b int
        |> field "c" .c (list float)
        |> field "d" .d (mylist bool)
        |> build


mylist : Meta a -> Meta (MyList a)
mylist e =
    let
        matchEmpty e =
            case e of
                Empty ->
                    Just ()

                _ ->
                    Nothing

        matchCons e =
            case e of
                Cons x xs ->
                    Just ( x, xs )

                _ ->
                    Nothing
    in
    adt
        [ alternative0 matchEmpty Empty
        , alternative2 matchCons Cons e (lazy (\_ -> mylist e))
        ]


exampleObject : ObjectSimpleFields
exampleObject =
    { a = "a"
    , b = 0
    , c = [ -1.3 ]
    , d = Cons False Empty
    }


main : Html msg
main =
    let
        (Meta { encode, decode }) =
            objectSimpleFieldsMeta

        encoded =
            encode exampleObject

        decoded =
            JD.decodeValue decode encoded
    in
    Html.span []
        [ Html.text "Encoded: "
        , Html.text <| toString encoded
        , Html.text " decoded: "
        , case decoded of
            Ok v ->
                Html.text <| toString v

            Err e ->
                String.split "\n" e
                    |> List.map Html.text
                    |> List.intersperse (Html.br [] [])
                    |> Html.span []
        ]


type Meta a
    = Meta
        { encode : a -> Value
        , decode : Decoder a
        }


string : Meta String
string =
    Meta
        { encode = JE.string
        , decode = JD.string
        }


int : Meta Int
int =
    Meta
        { encode = JE.int
        , decode = JD.int
        }


float : Meta Float
float =
    Meta
        { encode = JE.float
        , decode = JD.float
        }


bool : Meta Bool
bool =
    Meta
        { encode = JE.bool
        , decode = JD.bool
        }


list : Meta a -> Meta (List a)
list =
    bimap
        (\e -> JE.list << List.map e)
        JD.list


dict : Meta a -> Meta (Dict String a)
dict =
    bimap
        (\e -> JE.object << Dict.toList << Dict.map (always e))
        JD.dict


set : Meta comparable -> Meta (Set comparable)
set =
    bimap
        (\e -> JE.list << List.map e << Set.toList)
        (JD.map Set.fromList << JD.list)


bimap : ((a -> Value) -> b -> Value) -> (Decoder a -> Decoder b) -> Meta a -> Meta b
bimap menc mdec (Meta meta) =
    Meta
        { encode = menc meta.encode
        , decode = mdec meta.decode
        }


type ObjectMeta a b
    = ObjectMeta
        { encode : a -> List ( String, Value )
        , decode : Decoder b
        }


object : b -> ObjectMeta a b
object ctor =
    ObjectMeta
        { encode = always []
        , decode = JD.succeed ctor
        }


field : String -> (a -> f) -> Meta f -> ObjectMeta a (f -> b) -> ObjectMeta a b
field name getter (Meta meta) (ObjectMeta ometa) =
    ObjectMeta
        { encode = \v -> ( name, meta.encode <| getter v ) :: ometa.encode v
        , decode = JD.map2 (\f x -> f x) ometa.decode (JD.field name meta.decode)
        }


build : ObjectMeta a a -> Meta a
build (ObjectMeta ometa) =
    Meta
        { encode = JE.object << ometa.encode
        , decode = ometa.decode
        }


type AlternativeMeta a
    = AlternativeMeta
        { encode : a -> Maybe (List Value)
        , decode : Decoder a
        }


apply : Decoder a -> Decoder (a -> b) -> Decoder b
apply =
    JD.map2 (|>)


alternative : (a -> Maybe b) -> (b -> List Value) -> Decoder a -> AlternativeMeta a
alternative match toList ctor =
    AlternativeMeta
        { encode = match >> Maybe.map toList
        , decode = ctor
        }


alternative0 : (a -> Maybe ()) -> a -> AlternativeMeta a
alternative0 match ctor =
    alternative match (always []) (JD.succeed ctor)


alternative1 : (a -> Maybe b) -> (b -> a) -> Meta b -> AlternativeMeta a
alternative1 match ctor (Meta p1) =
    alternative
        match
        (\v1 -> [ p1.encode v1 ])
        (JD.succeed ctor
            |> apply (JD.field "0" p1.decode)
        )


alternative2 : (a -> Maybe ( b, c )) -> (b -> c -> a) -> Meta b -> Meta c -> AlternativeMeta a
alternative2 match ctor (Meta p1) (Meta p2) =
    alternative
        match
        (\( v1, v2 ) -> [ p1.encode v1, p2.encode v2 ])
        (JD.succeed ctor
            |> apply (JD.field "0" p1.decode)
            |> apply (JD.field "1" p2.decode)
        )


adt : List (AlternativeMeta a) -> Meta a
adt alternatives =
    let
        maybeEncode : a -> Int -> AlternativeMeta a -> Maybe ( Int, List Value )
        maybeEncode e i (AlternativeMeta { encode }) =
            encode e |> Maybe.map (\v -> ( i, v ))

        aencode e =
            alternatives
                |> List.indexedMap (maybeEncode e)
                |> List.filterMap identity
                |> List.head
                |> Maybe.map
                    (\( i, v ) ->
                        JE.object
                            [ ( "tag", JE.int i )
                            , ( "values", JE.list v )
                            ]
                    )
                |> Maybe.withDefault JE.null

        adecode =
            JD.field "tag" JD.int
                |> JD.andThen
                    (\tag ->
                        case List.drop tag alternatives of
                            [] ->
                                JD.fail <| "Wrong tag, got " ++ toString tag

                            (AlternativeMeta { decode }) :: _ ->
                                JD.field "values" decode
                    )
    in
    Meta
        { encode = aencode
        , decode = adecode
        }


lazy : (() -> Meta a) -> Meta a
lazy f =
    Meta
        { encode =
            \v ->
                let
                    (Meta { encode }) =
                        f ()
                in
                encode v
        , decode =
            JD.lazy
                (\l ->
                    let
                        (Meta { decode }) =
                            f l
                    in
                    decode
                )
        }

 newer latest older