on cd4f7e5 help sign in
49 files changed+317−1114
since splitsnapshots
unifiedsplit
.gitignore−1 LICENSE−7 README.md−11 dev/sink-elm-live.sh → dev/elm-live.sh+1−1 dev/vanilla-elm-live.sh−7 docs/sink.md−101 elm.json+2−11 example/urbit/app/journal.hoon → example/journal/app/journal.hoon+19−26 example/urbit/desk.bill → example/journal/desk.bill example/urbit/desk.docket-0 → example/journal/desk.docket-0 example/urbit/gen/journal/add.hoon → example/journal/gen/journal/add.hoon example/urbit/lib/agentio.hoon → example/journal/lib/agentio.hoon example/urbit/lib/dbug.hoon → example/journal/lib/dbug.hoon example/urbit/lib/default-agent.hoon → example/journal/lib/default-agent.hoon example/urbit/lib/docket.hoon → example/journal/lib/docket.hoon example/urbit/lib/journal.hoon → example/journal/lib/journal.hoon example/urbit/lib/skeleton.hoon → example/journal/lib/skeleton.hoon example/urbit/mar/bill.hoon → example/journal/mar/bill.hoon example/urbit/mar/docket-0.hoon → example/journal/mar/docket-0.hoon example/urbit/mar/hoon.hoon → example/journal/mar/hoon.hoon example/urbit/mar/jam.hoon → example/journal/mar/jam.hoon example/urbit/mar/journal/action.hoon → example/journal/mar/journal/action.hoon example/urbit/mar/journal/update.hoon → example/journal/mar/journal/update.hoon example/urbit/mar/json.hoon → example/journal/mar/json.hoon example/urbit/mar/kelvin.hoon → example/journal/mar/kelvin.hoon example/urbit/mar/mime.hoon → example/journal/mar/mime.hoon example/urbit/mar/noun.hoon → example/journal/mar/noun.hoon example/urbit/mar/txt-diff.hoon → example/journal/mar/txt-diff.hoon example/urbit/mar/txt.hoon → example/journal/mar/txt.hoon example/urbit/sur/docket.hoon → example/journal/sur/docket.hoon example/urbit/sur/journal.hoon → example/journal/sur/journal.hoon example/urbit/sys.kelvin → example/journal/sys.kelvin example/script.js+1−16 example/src/Vanilla.elm → example/src/Main.elm+16−21 example/src/Sink.elm−199 example/urbit/lib/noun-diff.hoon−227 example/urbit/lib/sink.hoon−26 src/BitWriter.elm+5−5 src/Ur.elm+2−2 src/Ur/Constructor.elm+2−2 src/Ur/Deconstructor.elm+218−211 src/Ur/NounDiff.elm−115 src/Ur/Phonemic.elm+1−1 src/Ur/Requests.elm+1−1 src/Ur/Run.elm+23−80 src/Ur/Sub.elm+6−21 src/Ur/Sub/Internal.elm+1−3 src/Ur/Uw.elm+8−8 tests/Test/Urbit.elm+11−11
.gitignore−1
@@ -1,3 +1,2 @@
11elm-stuff
22elm.js
3−zod
LICENSEdeleted−7
@@ -1,7 +0,0 @@
1−Copyright 2023 Ilia Kostiuchenko
2−
3−Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4−
5−The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6−
7−THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
README.md−11
@@ -4,19 +4,8 @@
44
55## Usage
66
7−### Demo
8−
9−[![DEMO](https://img.youtube.com/vi/tynCzifvIzE/0.jpg)](https://www.youtube.com/watch?v=tynCzifvIzE)
10−
11−
12−## Getting started
13−
14−The easiest way of using this library is by using the [airlock template](https://github.com/ilyakooo0/airlock-template).
15−
167### FFI
178
18−This is for setting up this library from scratch.
19−
209Urbit subscriptions require [server-side event (SSE)](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events).
2110Unfortunately, Elm does not provide a native implementation.
2211This means that we will need to use [JS FFI (aka ports)](https://guide.elm-lang.org/interop/ports.html).
dev/sink-elm-live.sh → dev/elm-live.shrenamed+1−1
@@ -4,4 +4,4 @@ set -e
44
55cd "$(dirname "$0")/../example"
66
7−nix run nixpkgs#elmPackages.elm-live -- src/Sink.elm --start-page=index.html -- --output=elm.js --debug "$@"
7+nix run nixpkgs#elmPackages.elm-live -- src/Main.elm --start-page=index.html -- --output=elm.js --debug "$@"
dev/vanilla-elm-live.shdeleted−7
@@ -1,7 +0,0 @@
1−#!/bin/sh
2−
3−set -e
4−
5−cd "$(dirname "$0")/../example"
6−
7−nix run nixpkgs#elmPackages.elm-live -- src/Vanilla.elm --start-page=index.html -- --output=elm.js --debug "$@"
docs/sink.mddeleted−101
@@ -1,101 +0,0 @@
1−# %sink
2−
3−%sink is a state replication system between your %gall agent and your Elm airlock.
4−
5−%sink allows you to avoid having to manually write subscriptions which send semantic diffs between your %gall agent and the frontend.
6−
7−## How it works
8−
9−%sink consists of two parts:
10−1. The %sink library you import into your %gall agent and call appropriate functions at the right points in your agent lifecycle. More on this in a bit.
11−2. The `Ur.Sub.sink` urbit subscription which reconciles the state and hands you the latest version of %gall agent state that you can then `Deconstruct` into Elm data structures.
12−
13−The whole system works by saving the previous version your %gall agent state and diffing the raw nouns that compose your old state and your new state.
14−On first initialization of the %sink system the whole state you supplied is sent to the frontend. Any subsequent changes are sent as a diff between your old state and your new state.
15−
16−## How to use it
17−
18−### The %gall agent part
19−
20−#### Copying library files
21−
22−In order to use %sink you have to copy the following two files into your agent desk into the `lib` directory:
23−1. [example/urbit/lib/noun-diff.hoon](../example/urbit/lib/noun-diff.hoon) -- contains the algorithm for diffing raw nouns.
24−2. [example/urbit/lib/sink.hoon](../example/urbit/lib/sink.hoon) -- contains the logic of syncing the state between your agent and your frontend.
25−
26−#### Adding sync points into your agent
27−
28−First you need to import the %sink library into your agent:
29−
30−```hoon
31−/+ *sink
32−```
33−
34−Next you need to initialize the sink. Put the following declaration somewhere before your agent door:
35−
36−```hoon
37−::
38−:: A deferred expression of the state you want to sync to the frontend.
39−=* entries (tap:j-orm journal.stat)
40−::
41−:: Replace /sync with whatever path you want to use for syncing your state.
42−=/ snik (sink ~[/sync])
43−::
44−:: Next you initialize your sink with your initial agent state.
45−=/ sink (snik entries)
46−```
47−
48−You can have multiple sinks in the same application to sync different parts of your state on different paths.
49−
50−Don't forget to reinitialize your `sink` when your restore your agent state in the `++on-load` arm:
51−
52−```hoon
53−++ on-load
54− |= old-vase=vase
55− ^- (quip card _this)
56− =/ state !<(versioned-state old-vase)
57− ::
58− :: the `sink (snik entries)` is the important bit.
59− `this(state state, sink (snik entries))
60−```
61−
62−Lastly, you need to send sink updates whenever you change your state. Most likely this will be in your `++on-poke` arm:
63−
64−```hoon
65−::
66−:: This line generates a `card` that you need to pass to arvo and updates
67−:: the `sink` to reference the latest state of your agent.
68−=^ card sink (sync:sink entries)
69−```
70−
71−You can look at the [journal.hoon](../example/urbit/app/journal.hoon) for a full example.
72−
73−#### Adding sink the the frontend
74−
75−For your frontend to recieve %sink updates you need to pass the result of calling `Ur.Sub.sink` to the `urbitSubscriptions` field of `Ur.Run.application` or similar function from `Ur.Run`:
76−
77−```elm
78−main : Ur.Run.Program Model Msg
79−main =
80− Ur.Run.application
81− {
82− -- ...
83− urbitSubscriptions =
84− -- ...
85− Ur.Sub.sink
86− { ship = ship
87− , app = "journal"
88− , path = [ "sync" ]
89− , deconstructor =
90− D.list (D.cell D.bigint D.cord |> D.map (\a b -> ( a, b )))
91− |> D.map GotListings
92− }
93− -- ...
94− }
95−```
96−
97−In the `deconstructor` field you specify a `Deconstructor` the deconstructs _the whole_ state that is being synced form the %gall agent.
98−
99−You do not have to deal with diffs. It is handled automatically
100−
101−You can look at [example/src/Sink.elm](../example/src/Sink.elm) for a full example.
elm.json+2−11
@@ -3,18 +3,9 @@
33 "name": "ilyakooo0/airlock",
44 "summary": "Urbit airlock",
55 "license": "MIT",
6− "version": "1.1.1",
6+ "version": "1.0.0",
77 "exposed-modules": [
8− "Ur",
9− "Ur.Cmd",
10− "Ur.Sub",
11− "Ur.Constructor",
12− "Ur.Deconstructor",
13− "Ur.Phonemic",
14− "Ur.Da",
15− "Ur.Uw",
16− "Ur.Run",
17− "Ur.Types"
8+ "Ur", "Ur.Cmd", "Ur.Sub", "Ur.Constructor", "Ur.Deconstructor", "Ur.Phonemic", "Ur.Da", "Ur.Uw", "Ur.Run", "Ur.Types"
189 ],
1910 "elm-version": "0.19.0 <= v < 0.20.0",
2011 "dependencies": {
example/urbit/app/journal.hoon → example/journal/app/journal.hoonrenamed+19−26
@@ -1,5 +1,5 @@
11/- *journal
2−/+ default-agent, dbug, agentio, *sink
2+/+ default-agent, dbug, agentio
33|%
44+$ versioned-state
55 $% state-0
@@ -17,15 +17,11 @@
1717 ?. (has:log-orm log unix-ms)
1818 unix-ms
1919 $(time (add unix-ms 1))
20−--
21−
20+--
2221%- agent:dbug
23−=/ state *state-0
24−=* entries (tap:j-orm journal.state)
25−=/ snik (sink ~[/sync])
26−=/ sink (snik entries)
22+=| state-0
23+=* state -
2724^- agent:gall
28−::
2925|_ =bowl:gall
3026+* this .
3127 def ~(. (default-agent this %|) bowl)
@@ -38,8 +34,7 @@
3834++ on-load
3935 |= old-vase=vase
4036 ^- (quip card _this)
41− =/ state !<(versioned-state old-vase)
42− `this(state state, sink (snik entries))
37+ `this(state !<(versioned-state old-vase))
4338::
4439++ on-poke
4540 |= [=mark =vase]
@@ -47,28 +42,27 @@
4742 |^
4843 ?> (team:title our.bowl src.bowl)
4944 ?. ?=(%journal-action mark) (on-poke:def mark vase)
50− =/ now=@ (unique-time now.bowl log.state)
45+ =/ now=@ (unique-time now.bowl log)
5146 =/ act !<(action vase)
5247 =. state (poke-action act)
53− =^ card sink (sync:sink entries)
54− :_ this(log.state (put:log-orm log.state now act))
55− ~[(fact:io journal-update+!>(`update`[now act]) ~[/updates]) card]
48+ :_ this(log (put:log-orm log now act))
49+ ~[(fact:io journal-update+!>(`update`[now act]) ~[/updates])]
5650 ::
5751 ++ poke-action
5852 |= act=action
5953 ^- _state
6054 ?- -.act
6155 %add
62− ?< (has:j-orm journal.state id.act)
63− state(journal (put:j-orm journal.state id.act txt.act))
56+ ?< (has:j-orm journal id.act)
57+ state(journal (put:j-orm journal id.act txt.act))
6458 ::
6559 %edit
66− ?> (has:j-orm journal.state id.act)
67− state(journal (put:j-orm journal.state id.act txt.act))
60+ ?> (has:j-orm journal id.act)
61+ state(journal (put:j-orm journal id.act txt.act))
6862 ::
6963 %del
70− ?> (has:j-orm journal.state id.act)
71− state(journal +:(del:j-orm journal.state id.act))
64+ ?> (has:j-orm journal id.act)
65+ state(journal +:(del:j-orm journal id.act))
7266 ==
7367 --
7468::
@@ -78,7 +72,6 @@
7872 ?> (team:title our.bowl src.bowl)
7973 ?+ path (on-watch:def path)
8074 [%updates ~] `this
81− [%sync ~] [~[flush:sink] this]
8275 ==
8376::
8477++ on-peek
@@ -92,14 +85,14 @@
9285 [%all ~]
9386 :^ ~ ~ %journal-update
9487 !> ^- update
95− [now %jrnl entries]
88+ [now %jrnl (tap:j-orm journal)]
9689 ::
9790 [%before @ @ ~]
9891 =/ before=@ (rash i.t.t.t.path dem)
9992 =/ max=@ (rash i.t.t.t.t.path dem)
10093 :^ ~ ~ %journal-update
10194 !> ^- update
102− [now %jrnl (tab:j-orm journal.state `before max)]
95+ [now %jrnl (tab:j-orm journal `before max)]
10396 ::
10497 [%between @ @ ~]
10598 =/ start=@
@@ -108,7 +101,7 @@
108101 =/ end=@ (add 1 (rash i.t.t.t.t.path dem))
109102 :^ ~ ~ %journal-update
110103 !> ^- update
111− [now %jrnl (tap:j-orm (lot:j-orm journal.state `end `start))]
104+ [now %jrnl (tap:j-orm (lot:j-orm journal `end `start))]
112105 ==
113106 ::
114107 [%x %updates *]
@@ -116,13 +109,13 @@
116109 [%all ~]
117110 :^ ~ ~ %journal-update
118111 !> ^- update
119− [now %logs (tap:log-orm log.state)]
112+ [now %logs (tap:log-orm log)]
120113 ::
121114 [%since @ ~]
122115 =/ since=@ (rash i.t.t.t.path dem)
123116 :^ ~ ~ %journal-update
124117 !> ^- update
125− [now %logs (tap:log-orm (lot:log-orm log.state `since ~))]
118+ [now %logs (tap:log-orm (lot:log-orm log `since ~))]
126119 ==
127120 ==
128121::
example/urbit/desk.bill → example/journal/desk.billrenamed

The content is the same.

example/urbit/desk.docket-0 → example/journal/desk.docket-0renamed

The content is the same.

example/urbit/gen/journal/add.hoon → example/journal/gen/journal/add.hoonrenamed

The content is the same.

example/urbit/lib/agentio.hoon → example/journal/lib/agentio.hoonrenamed

The content is the same.

example/urbit/lib/dbug.hoon → example/journal/lib/dbug.hoonrenamed

The content is the same.

example/urbit/lib/default-agent.hoon → example/journal/lib/default-agent.hoonrenamed

The content is the same.

example/urbit/lib/docket.hoon → example/journal/lib/docket.hoonrenamed

The content is the same.

example/urbit/lib/journal.hoon → example/journal/lib/journal.hoonrenamed

The content is the same.

example/urbit/lib/skeleton.hoon → example/journal/lib/skeleton.hoonrenamed

The content is the same.

example/urbit/mar/bill.hoon → example/journal/mar/bill.hoonrenamed

The content is the same.

example/urbit/mar/docket-0.hoon → example/journal/mar/docket-0.hoonrenamed

The content is the same.

example/urbit/mar/hoon.hoon → example/journal/mar/hoon.hoonrenamed

The content is the same.

example/urbit/mar/jam.hoon → example/journal/mar/jam.hoonrenamed

The content is the same.

example/urbit/mar/journal/action.hoon → example/journal/mar/journal/action.hoonrenamed

The content is the same.

example/urbit/mar/journal/update.hoon → example/journal/mar/journal/update.hoonrenamed

The content is the same.

example/urbit/mar/json.hoon → example/journal/mar/json.hoonrenamed

The content is the same.

example/urbit/mar/kelvin.hoon → example/journal/mar/kelvin.hoonrenamed

The content is the same.

example/urbit/mar/mime.hoon → example/journal/mar/mime.hoonrenamed

The content is the same.

example/urbit/mar/noun.hoon → example/journal/mar/noun.hoonrenamed

The content is the same.

example/urbit/mar/txt-diff.hoon → example/journal/mar/txt-diff.hoonrenamed

The content is the same.

example/urbit/mar/txt.hoon → example/journal/mar/txt.hoonrenamed

The content is the same.

example/urbit/sur/docket.hoon → example/journal/sur/docket.hoonrenamed

The content is the same.

example/urbit/sur/journal.hoon → example/journal/sur/journal.hoonrenamed

The content is the same.

example/urbit/sys.kelvin → example/journal/sys.kelvinrenamed

The content is the same.

example/script.js+1−16
@@ -2,22 +2,7 @@ import { fetchEventSource } from "/fetch-event-source.js"
22
33const uid = `${Math.floor(Date.now() / 1000)}-${Math.random()}`;
44
5−function searchForInit(obj) {
6− if (obj.init) {
7− return obj.init;
8− } else {
9− for (let key in obj) {
10− if (obj.hasOwnProperty(key)) {
11− const result = searchForInit(obj[key]);
12− if (result) {
13− return result;
14− }
15− }
16− }
17− }
18−}
19−
20−let app = searchForInit(Elm)({ node: document.getElementById("elm"), flags: { uid } });
5+let app = Elm.Main.init({ node: document.getElementById("elm"), flags: { uid } });
216
227app.ports.createEventSource.subscribe((url) => {
238 fetchEventSource(url, {
example/src/Vanilla.elm → example/src/Main.elmrenamed+16−21
@@ -1,4 +1,4 @@
1−port module Vanilla exposing (main)
1+port module Main exposing (main)
22
33import BigInt exposing (BigInt)
44import Browser exposing (Document)
@@ -12,6 +12,7 @@ import Ur
1212import Ur.Cmd
1313import Ur.Constructor as C
1414import Ur.Deconstructor as D
15+import Ur.Requests
1516import Ur.Run
1617import Ur.Sub
1718import Widget
@@ -19,11 +20,6 @@ import Widget.Icon as Icon
1920import Widget.Material as Material
2021
2122
22−url : String
23−url =
24− "http://localhost:8080"
25−
26−
2723main : Ur.Run.Program Model Msg
2824main =
2925 Ur.Run.application
@@ -35,20 +31,20 @@ main =
3531 , shipName = Nothing
3632 }
3733 , Cmd.batch
38− [ Ur.logIn url "lidlut-tabwed-pillex-ridrup"
34+ [ Ur.logIn "http://localhost:8080" "lidlut-tabwed-pillex-ridrup"
3935 |> Cmd.map (result (Debug.toString >> Error) (always Noop))
40− , Ur.getShipName url |> Cmd.map (result (always Noop) GotShipName)
41− , Ur.scry
42− { url = url
36+ , Ur.getShipName "http://localhost:8080" |> Cmd.map (result (always Noop) GotShipName)
37+ , Ur.Requests.scry
38+ { url = "http://localhost:8080"
4339 , agent = "journal"
4440 , path = [ "entries", "all" ]
4541 , error = Noop
4642 , success =
4743 D.cell D.ignore
4844 (D.cell (D.const D.cord "jrnl")
49− (D.list (D.cell D.bigint D.cord))
45+ (D.list (D.cell D.bigint D.cord |> D.map (\a b -> ( a, b ))))
46+ |> D.map GotListings
5047 )
51− |> D.map (\( (), ( (), listings ) ) -> GotListings listings)
5248 }
5349 ]
5450 |> Ur.Cmd.cmd
@@ -73,7 +69,7 @@ main =
7369 , onEventSourceMsg = onEventSourceMessage
7470 , onUrlChange = \_ -> Noop
7571 , onUrlRequest = \_ -> Noop
76− , urbitUrl = \_ -> url
72+ , urbitUrl = \_ -> "http://localhost:8080"
7773 }
7874
7975
@@ -177,15 +173,14 @@ type JournalUpdate
177173 | Delete BigInt
178174
179175
180−decodeJournalUpdate : D.Deconstructor JournalUpdate
176+decodeJournalUpdate : D.Deconstructor (JournalUpdate -> a) a
181177decodeJournalUpdate =
182− D.oneOf
183− [ (D.cell (D.const D.cord "add") <| D.cell D.bigint D.cord) |> D.map (\( (), ( id, txt ) ) -> Add id txt)
184− , D.cell (D.const D.cord "edit") (D.cell D.bigint D.cord) |> D.map (\( (), ( id, txt ) ) -> Edit id txt)
185− , D.cell (D.const D.cord "del") D.bigint |> D.map (\( (), id ) -> Delete id)
186− ]
187− |> D.cell D.ignore
188− |> D.map (\( (), upd ) -> upd)
178+ D.cell D.ignore <|
179+ D.oneOf
180+ [ (D.cell (D.const D.cord "add") <| D.cell D.bigint D.cord) |> D.map Add
181+ , (D.cell (D.const D.cord "edit") <| D.cell D.bigint D.cord) |> D.map Edit
182+ , D.cell (D.const D.cord "del") D.bigint |> D.map Delete
183+ ]
189184
190185
191186view : Model -> Document Msg
example/src/Sink.elmdeleted−199
@@ -1,199 +0,0 @@
1−port module Sink exposing (main)
2−
3−import BigInt exposing (BigInt)
4−import Browser exposing (Document)
5−import Element exposing (..)
6−import Element.Border as Border
7−import Heroicons.Outline
8−import Json.Decode as JD
9−import Task
10−import Time
11−import Ur
12−import Ur.Cmd
13−import Ur.Constructor as C
14−import Ur.Deconstructor as D
15−import Ur.Run
16−import Ur.Sub
17−import Widget
18−import Widget.Icon as Icon
19−import Widget.Material as Material
20−
21−
22−url : String
23−url =
24− "http://localhost:8080"
25−
26−
27−main : Ur.Run.Program Model Msg
28−main =
29− Ur.Run.application
30− { init =
31− \_ _ ->
32− ( { error = ""
33− , entries = Nothing
34− , newEntry = ""
35− , shipName = Nothing
36− }
37− , Cmd.batch
38− [ Ur.logIn url "lidlut-tabwed-pillex-ridrup"
39− |> Cmd.map (result (Debug.toString >> Error) (always Noop))
40− , Ur.getShipName url |> Cmd.map (result (always Noop) GotShipName)
41− ]
42− |> Ur.Cmd.cmd
43− )
44− , update = update
45− , view = view
46− , subscriptions = always Sub.none
47− , createEventSource = createEventSource
48− , urbitSubscriptions =
49− \{ shipName } ->
50− case shipName of
51− Just ship ->
52− Ur.Sub.batch
53− [ Ur.Sub.sink
54− { ship = ship
55− , app = "journal"
56− , path = [ "sync" ]
57− , deconstructor =
58− D.list (D.cell D.bigint D.cord)
59− |> D.map GotListings
60− }
61− ]
62−
63− _ ->
64− Ur.Sub.none
65− , onEventSourceMsg = onEventSourceMessage
66− , onUrlChange = \_ -> Noop
67− , onUrlRequest = \_ -> Noop
68− , urbitUrl = \_ -> url
69− }
70−
71−
72−type alias Model =
73− { error : String
74− , entries : Maybe (List ( BigInt, String ))
75− , newEntry : String
76− , shipName : Maybe String
77− }
78−
79−
80−type Msg
81− = Noop
82− | Error String
83− | GotListings (List ( BigInt, String ))
84− | UpdateNewEntry String
85− | DeleteEntry BigInt
86− | AddEntry String
87− | RunCmd (Ur.Cmd.Cmd Msg)
88− | GotShipName String
89−
90−
91−update : Msg -> Model -> ( Model, Ur.Cmd.Cmd Msg )
92−update msg model =
93− case msg of
94− Noop ->
95− ( model, Ur.Cmd.none )
96−
97− Error err ->
98− ( { model | error = err }, Ur.Cmd.none )
99−
100− GotListings entries ->
101− ( { model | entries = Just entries }, Ur.Cmd.none )
102−
103− UpdateNewEntry txt ->
104− ( { model | newEntry = txt }, Ur.Cmd.none )
105−
106− DeleteEntry id ->
107− ( model
108− , Ur.Cmd.poke
109− { ship = "~zod"
110− , agent = "journal"
111− , mark = "journal-action"
112− , noun = C.cell (C.cord "del") (C.bigint id)
113− }
114− )
115−
116− AddEntry txt ->
117− ( { model | newEntry = "" }
118− , Time.now
119− |> Task.perform
120− (\time ->
121− Ur.Cmd.poke
122− { ship = "~zod"
123− , agent = "journal"
124− , mark = "journal-action"
125− , noun = C.cell (C.cord "add") (C.cell (time |> Time.posixToMillis |> BigInt.fromInt |> C.bigint) (C.cord txt))
126− }
127− |> RunCmd
128− )
129− |> Ur.Cmd.cmd
130− )
131−
132− RunCmd cmd ->
133− ( model, cmd )
134−
135− GotShipName name ->
136− ( { model | shipName = Just name }, Ur.Cmd.none )
137−
138−
139−view : Model -> Document Msg
140−view model =
141− { body =
142− [ layout []
143− ([ el [ alignTop ] (text model.error)
144− , row [ spacing 8 ]
145− [ Widget.textInput (Material.textInput Material.defaultPalette)
146− { chips = []
147− , text = model.newEntry
148− , placeholder = Nothing
149− , label = "New entry"
150− , onChange = UpdateNewEntry
151− }
152− , Widget.iconButton (Material.containedButton Material.defaultPalette)
153− { text = "submit"
154− , icon = Icon.elmHeroicons Heroicons.Outline.check
155− , onPress = AddEntry model.newEntry |> Just
156− }
157− ]
158− , model.entries
159− |> Maybe.withDefault []
160− |> List.map
161− (\( id, txt ) ->
162− row
163− [ Border.rounded 10
164− , Border.shadow { offset = ( 0, 5 ), size = 1, blur = 10, color = rgba 0 0 0 0.3 }
165− , centerX
166− , padding 10
167− , spacing 12
168− ]
169− [ paragraph [] [ text txt ]
170− , Widget.iconButton (Material.containedButton Material.defaultPalette)
171− { text = "delete"
172− , icon = Icon.elmHeroicons Heroicons.Outline.trash
173− , onPress = DeleteEntry id |> Just
174− }
175− ]
176− )
177− |> column [ spacing 10, centerX ]
178− ]
179− |> column [ spacing 18, centerX ]
180− )
181− ]
182− , title = "Airlock"
183− }
184−
185−
186−result : (a -> c) -> (b -> c) -> Result a b -> c
187−result f g res =
188− case res of
189− Ok b ->
190− g b
191−
192− Err a ->
193− f a
194−
195−
196−port createEventSource : String -> Cmd msg
197−
198−
199−port onEventSourceMessage : (JD.Value -> msg) -> Sub msg
example/urbit/lib/noun-diff.hoondeleted−227
@@ -1,227 +0,0 @@
1−=<
2−|%
3− ++ diff
4− |= [old=* new=*]
5− ^- patch
6− =/ del (extract-del (oracle old new) old)
7− =/ ins (extract-ins (oracle old new) new)
8− =/ allowed-holes (~(int in (find-del-holes del)) (find-ins-holes ins))
9− =. del (filter-del-holes allowed-holes del)
10− =/ ins (filter-ins-holes allowed-holes ins)
11− =/ closed-patch (closure (gcp [del ins]))
12− ?> =(& +.closed-patch)
13− -.closed-patch
14− ++ apply
15− |= [patch=_id noun=*]
16− ?- -.patch
17− %diff
18− =/ var-map (del del.patch noun)
19− (ins ins.patch var-map)
20− %cell
21− ?> ?=(^ noun)
22− [$(patch lhs.patch, noun -.noun) $(patch rhs.patch, noun +.noun)]
23− ==
24− ++ id
25− ^- patch
26− [%diff [%hole ~] [%hole ~]]
27− +$ patch
28− $%
29− [%cell lhs=patch rhs=patch]
30− [%diff ^diff]
31− ==
32−--
33−::
34−|%
35− +$ del-diff
36− $%
37− [%hole @]
38− [%cell lhs=del-diff rhs=del-diff]
39− [%ignore ~]
40− ==
41− +$ ins-diff
42− $%
43− [%hole @ original=*]
44− [%cell lhs=ins-diff rhs=ins-diff]
45− [%atom @]
46− ==
47− +$ final-ins-diff
48− $%
49− [%hole @]
50− [%cell lhs=final-ins-diff rhs=final-ins-diff]
51− [%atom @]
52− ==
53− +$ diff [del=del-diff ins=final-ins-diff]
54− +$ patch
55− $%
56− [%cell lhs=patch rhs=patch]
57− [%diff diff]
58− ==
59− ++ insify-noun
60− |= noun=*
61− ^- final-ins-diff
62− ?- noun
63− ^ [%cell $(noun -.noun) $(noun +.noun)]
64− @ [%atom noun]
65− ==
66− ++ empty-set (silt `(list @)`~)
67− ++ find-del-holes
68− |= diff=del-diff
69− ~+
70− ^- (set @)
71− ?- -.diff
72− %hole (silt ~[+.diff])
73− %cell
74− (~(uni in $(diff lhs.diff)) $(diff rhs.diff))
75− %ignore empty-set
76− ==
77− ++ find-final-ins-holes
78− |= diff=final-ins-diff
79− ~+
80− ^- (set @)
81− ?- -.diff
82− %hole (silt ~[+.diff])
83− %cell
84− (~(uni in $(diff lhs.diff)) $(diff rhs.diff))
85− %atom empty-set
86− ==
87− ++ find-ins-holes
88− |= diff=ins-diff
89− ~+
90− ^- (set @)
91− ?- -.diff
92− %hole (silt ~[+<.diff])
93− %cell
94− (~(uni in $(diff lhs.diff)) $(diff rhs.diff))
95− %atom empty-set
96− ==
97− ++ filter-del-holes
98− |= [allowed-holes=(set @) diff=del-diff]
99− ^- del-diff
100− ?: ?=(%ignore -.diff) diff
101− ?- -.diff
102− %hole
103− ?: (~(has in allowed-holes) +.diff) diff
104− [%ignore ~]
105− %cell [%cell $(diff +<.diff) $(diff +>.diff)]
106− ==
107− ++ filter-ins-holes
108− |= [allowed-holes=(set @) diff=ins-diff]
109− ^- final-ins-diff
110− ?- -.diff
111− %hole
112− ?: (~(has in allowed-holes) +<.diff) [%hole +<.diff]
113− (insify-noun original:diff)
114− %cell [%cell $(diff +<.diff) $(diff +>.diff)]
115− %atom diff
116− ==
117− ++ gcp
118− |= diff=diff
119− ^- patch
120− ?- -.ins.diff
121− %atom
122− [%diff diff]
123− %cell
124− ?: ?=(%cell -.del.diff)
125− [%cell $(diff [+<.del.diff +<.ins.diff]) $(diff [+>.del.diff +>.ins.diff])]
126− [%diff diff]
127− %hole
128− [%diff diff]
129− ==
130− ++ closure
131− |= =patch
132− ^- [^patch ?]
133− ?- -.patch
134− %diff
135− =/ del-holes (find-del-holes del:patch)
136− =/ ins-holes (find-final-ins-holes ins:patch)
137− =/ difference (~(dif in ins-holes) del-holes)
138− [patch =(difference empty-set)]
139− %cell
140− =/ lhs $(patch lhs:patch)
141− =/ rhs $(patch rhs:patch)
142− ?: ?&(+.lhs +.rhs) [[%cell -.lhs -.rhs] &]
143− $(patch (pull-diff [%cell -.lhs -.rhs]))
144− ==
145− ++ pull-diff
146− |= =patch
147− ^- [%diff del=del-diff ins=final-ins-diff]
148− ?- -.patch
149− %diff patch
150− %cell
151− =/ pulled-lhs $(patch lhs:patch)
152− =/ pulled-rhs $(patch rhs:patch)
153− :+
154− %diff
155− [%cell del:pulled-lhs del:pulled-rhs]
156− [%cell ins:pulled-lhs ins:pulled-rhs]
157− ==
158− ++ is-subtree
159− |= [tree=* subtree=*]
160− ~+
161− ^- ?
162− ?: =(tree subtree) &
163− ?@ tree |
164− ?|
165− (is-subtree -.tree subtree)
166− (is-subtree +.tree subtree)
167− ==
168− ++ oracle
169− |= [a=* b=*]
170− |= subtree=*
171− ^- (unit @)
172− ?:
173− ?&
174− (is-subtree a subtree)
175− (is-subtree b subtree)
176− ==
177− `(mug subtree)
178− ~
179− ++ extract-del
180− |= [oracle=$-(* (unit @)) subtree=*]
181− ~+
182− ^- del-diff
183− =/ hash (oracle subtree)
184− ?^ hash [%hole +.hash]
185− ?@ subtree [%ignore ~]
186− [%cell (extract-del oracle -.subtree) (extract-del oracle +.subtree)]
187− ++ extract-ins
188− |= [oracle=$-(* (unit @)) subtree=*]
189− ~+
190− ^- ins-diff
191− =/ hash (oracle subtree)
192− ?^ hash [%hole +.hash subtree]
193− ?@ subtree [%atom subtree]
194− [%cell (extract-ins oracle -.subtree) (extract-ins oracle +.subtree)]
195− ++ ins
196− |= [diff=final-ins-diff var-map=(map @ *)]
197− ^- *
198− ?- -.diff
199− %atom
200− +.diff
201− %cell
202− [$(diff +<.diff) $(diff +>.diff)]
203− %hole
204− (~(got by var-map) +.diff)
205− ==
206− ++ del
207− |= [diff=del-diff noun=*]
208− ^- (map @ *)
209− |^ (go diff noun ((map @ *) ~))
210− ++ go
211− |= [diff=del-diff noun=* var-map=(map @ *)]
212− ^- (map @ *)
213− ?- -.diff
214− %ignore var-map
215− %hole
216− =/ subtree (~(get by var-map) +.diff)
217− ?~ subtree (~(put by var-map) +.diff noun)
218− ?> =(+.subtree noun)
219− var-map
220− %cell
221− ?> ?=(^ noun)
222− =/ lhs-var-map $(diff +<.diff, noun -.noun)
223− =/ rhs-var-map $(diff +>.diff, noun +.noun, var-map lhs-var-map)
224− rhs-var-map
225− ==
226− --
227−--
example/urbit/lib/sink.hoondeleted−26
@@ -1,26 +0,0 @@
1−/+ noun-diff
2−|%
3−++ clog
4− |$ [stut]
5− $%
6− [%flush stut]
7− [%drain patch:noun-diff]
8− ==
9−++ sink
10− |* pats=(list path)
11− |* stat=*
12− |@
13− ++ sync
14− |= [stat=_stat]
15− ^- [card:agent:gall _..sync]
16− =/ dif
17− %+ diff:noun-diff ^stat stat
18− :-
19− [%give %fact pats %noun !>(^-((clog) [%drain dif]))]
20− ..sync(stat stat)
21− ++ paths pats
22− ++ flush
23− ^- card:agent:gall
24− [%give %fact pats %noun !>(^-((clog) [%flush stat]))]
25− --
26−--
src/BitWriter.elm+5−5
@@ -14,17 +14,17 @@ import Bytes.Encode as BE
1414
1515empty : BitWriter
1616empty =
17− BitWriter { running = Nothing, collected = [], offset = 0 }
17+ BitWriter { running = Nothing, collected = BE.sequence [], offset = 0 }
1818
1919
2020run : BitWriter -> Bytes
2121run (BitWriter { running, collected }) =
2222 case running of
2323 Nothing ->
24− BE.encode (collected |> List.reverse |> BE.sequence)
24+ BE.encode collected
2525
2626 Just { value } ->
27− BE.sequence (BE.unsignedInt8 value :: collected |> List.reverse) |> BE.encode
27+ BE.sequence [ collected, BE.unsignedInt8 value ] |> BE.encode
2828
2929
3030type BitWriter
@@ -35,7 +35,7 @@ type BitWriter
3535 , length : Int
3636 }
3737 , offset : Int
38− , collected : List BE.Encoder
38+ , collected : BE.Encoder
3939 }
4040
4141
@@ -68,7 +68,7 @@ bit b (BitWriter { running, collected, offset }) =
6868 if length == 7 then
6969 BitWriter
7070 { running = Nothing
71− , collected = BE.unsignedInt8 newValue :: collected
71+ , collected = BE.sequence [ collected, BE.unsignedInt8 newValue ]
7272 , offset = newOffset
7373 }
7474
src/Ur.elm+2−2
@@ -77,7 +77,7 @@ scry :
7777 , agent : Agent
7878 , path : Path
7979 , error : msg
80− , success : D.Deconstructor msg
80+ , success : D.Deconstructor (msg -> msg) msg
8181 }
8282 -> Cmd msg
8383scry args =
@@ -91,7 +91,7 @@ scryTask :
9191 , agent : Agent
9292 , path : Path
9393 , error : msg
94− , success : D.Deconstructor msg
94+ , success : D.Deconstructor (msg -> msg) msg
9595 }
9696 -> Task a msg
9797scryTask { url, agent, path, error, success } =
src/Ur/Constructor.elm+2−2
@@ -89,7 +89,7 @@ signedInt i =
8989 )
9090
9191
92−{-| Constructs an `Atom` from `Bytes`.
92+{-| Constructs an `Atom` from `Bytes`
9393-}
9494bytes : Bytes -> Noun
9595bytes =
@@ -103,7 +103,7 @@ cord s =
103103 Atom (BE.encode (BE.string s))
104104
105105
106−{-| Constructs a [`tape`](https://developers.urbit.org/reference/glossary/tape) from a `String`.
106+{-| Constructs a [`tape`](https://developers.urbit.org/reference/glossary/tape) from a `String`
107107-}
108108tape : String -> Noun
109109tape s =
src/Ur/Deconstructor.elm+218−211
@@ -6,16 +6,24 @@ module Ur.Deconstructor exposing
66 , int, signedInt, bigint
77 , float32, float64
88 , cord, tape
9− , bytes, sig, ignore, tar, lazy, debug
9+ , bytes, sig, ignore, tar
1010 )
1111
1212{-| This module provides an API to deconstruct `Noun`s into arbitrary Elm data structures.
1313
14−You would parse a `[%edit @ cord]` like this:
14+The principal (and types) are very similar to `Url.Parser` from `elm/url`.
1515
16− type alias Edit = {id: Int, text : String}
16+You would parse a `[%edit cord @]` like this:
1717
18− (D.cell (D.const D.cord "edit") (D.cell D.bigint D.cord)) |> D.map (\( (), ( id, txt ) ) -> Edit id txt)
18+ type alias Edit = {text : String, id: Int}
19+
20+ (D.cell (D.const D.cord "edit") (D.cell D.int D.cord)) |> D.map Edit
21+
22+When you `map` a `Deconstructor` the function you pass to `map` will accept exactly the number of arguments
23+that "captured" values in exacly the order they occured in the `Deconstructor`.
24+
25+In our case we `map` the `Edit` type, which accepts exaclty two arguments because there are two `Deconstructor`s
26+that "capture" a value: `D.int` and `D.cord`.
1927
2028@docs Deconstructor
2129
@@ -55,7 +63,7 @@ You would parse a `[%edit @ cord]` like this:
5563
5664# Miscellaneous
5765
58−@docs bytes, sig, ignore, tar, lazy, debug
66+@docs bytes, sig, ignore, tar
5967
6068-}
6169
@@ -66,74 +74,139 @@ import Bytes exposing (Bytes, Endianness(..))
6674import Bytes.Decode as BD
6775import Bytes.Encode as BE
6876import Bytes.Extra
69−import Ur.Jam exposing (cue, isSig)
77+import Ur.Jam exposing (cue)
7078import Ur.Types exposing (..)
7179
7280
7381{-| A `Noun` deconstructor.
7482-}
75−type alias Deconstructor a =
76− Noun -> Maybe a
83+type Deconstructor a b
84+ = Deconstructor (Noun -> a -> Maybe b)
7785
7886
7987{-| Executes a `Deconstructor` on a `Noun`.
8088-}
81−run : Deconstructor a -> Noun -> Maybe a
82−run f noun =
83− f noun
89+run : Deconstructor (a -> a) a -> Noun -> Maybe a
90+run (Deconstructor f) noun =
91+ f noun identity
8492
8593
8694{-| Executes a deconstructor on a `jam`med `Noun`.
8795-}
88−runBytes : Deconstructor a -> Bytes -> Maybe a
89−runBytes f bs =
90− cue bs |> Maybe.andThen f
96+runBytes : Deconstructor (a -> a) a -> Bytes -> Maybe a
97+runBytes (Deconstructor f) bs =
98+ cue bs
99+ |> Maybe.andThen
100+ (\noun -> f noun identity)
91101
92102
93−{-| Asserts that the value should be exactly equal to the second argument.
103+{-| Asserts that the value at the current position should be exactly equal to the second argument.
94104
95−The first argument is a `Deconstructor` for the given type.
105+The first argument is a `Deconstructor` for the gven tyoe.
96106
97107The second argument is the value to compare with.
98108
99109This is useful to match on `term`s when there are multiple possible cases in a head-tagged union.
100110
101111-}
102−const : Deconstructor a -> a -> Deconstructor ()
103−const f value noun =
104− case f noun of
105− Just a ->
106− if a == value then
107− Just ()
112+const : Deconstructor (a -> a) a -> a -> Deconstructor c c
113+const (Deconstructor f) value =
114+ Deconstructor
115+ (\noun c ->
116+ case f noun identity of
117+ Just a ->
118+ if a == value then
119+ Just c
108120
109− else
110− Nothing
121+ else
122+ Nothing
111123
112− Nothing ->
113− Nothing
124+ Nothing ->
125+ Nothing
126+ )
114127
115128
116−{-| Extracts a `BigInt`.
129+{-| Extracts a `cord` at the current location.
117130-}
118−bigint : Deconstructor BigInt
119−bigint x =
120− case x of
121− Atom bs ->
122− BigInt.Bytes.decode bs |> Just
131+cord : Deconstructor (String -> a) a
132+cord =
133+ Deconstructor
134+ (\x f ->
135+ case x of
136+ Atom bs ->
137+ BD.decode (BD.string (Bytes.width bs)) bs
138+ |> Maybe.map f
139+
140+ Cell _ ->
141+ Nothing
142+ )
123143
124− Cell _ ->
125− Nothing
144+
145+{-| Extracts a `tape` at the current location.
146+-}
147+tape : Deconstructor (String -> a) a
148+tape =
149+ list cord |> fmap String.concat
126150
127151
128−{-| Extracts a 32-bit signed `Int`.
152+{-| Extracts a 32-bit unsigned `Int` at the given location.
129153
130−If the `Atom` is larger than 32 bits the the behaviour is undefined.
154+If the `Atom` at the current location is larger than 32 bits the the behaviour is undefined.
131155
132156-}
133−signedInt : Deconstructor Int
157+int : Deconstructor (Int -> a) a
158+int =
159+ Deconstructor
160+ (\x f ->
161+ case x of
162+ Atom bs ->
163+ (case Bytes.width bs of
164+ 1 ->
165+ BD.decode BD.unsignedInt8 bs
166+
167+ 2 ->
168+ BD.decode (BD.unsignedInt16 LE) bs
169+
170+ 3 ->
171+ BD.decode (BD.unsignedInt32 LE) (BE.encode (BE.sequence [ BE.bytes bs, BE.unsignedInt8 0 ]))
172+
173+ 4 ->
174+ BD.decode (BD.unsignedInt32 LE) bs
175+
176+ _ ->
177+ Nothing
178+ )
179+ |> Maybe.map f
180+
181+ Cell _ ->
182+ Nothing
183+ )
184+
185+
186+{-| Extracts a `BigInt` at the current location.
187+-}
188+bigint : Deconstructor (BigInt -> a) a
189+bigint =
190+ Deconstructor
191+ (\x f ->
192+ case x of
193+ Atom bs ->
194+ BigInt.Bytes.decode bs |> f |> Just
195+
196+ Cell _ ->
197+ Nothing
198+ )
199+
200+
201+{-| Extracts a 32-bit signed `Int` at the given location.
202+
203+If the `Atom` at the current location is larger than 32 bits the the behaviour is undefined.
204+
205+-}
206+signedInt : Deconstructor (Int -> a) a
134207signedInt =
135208 int
136− |> map
209+ |> fmap
137210 (\i ->
138211 if Bitwise.and 1 i == 1 then
139212 -(Bitwise.shiftRightBy 1 (1 + i))
@@ -143,85 +216,105 @@ signedInt =
143216 )
144217
145218
146−{-| Extracts a 32-bit `Float`.
219+{-| Extracts a 32-bit `Float` at the given location.
147220-}
148−float32 : Deconstructor Float
149−float32 x =
150− case x of
151− Atom bs ->
152− BD.decode (BD.float32 LE) bs
153−
154− Cell _ ->
155− Nothing
221+float32 : Deconstructor (Float -> a) a
222+float32 =
223+ Deconstructor
224+ (\x f ->
225+ case x of
226+ Atom bs ->
227+ BD.decode (BD.float32 LE) bs
228+ |> Maybe.map f
229+
230+ Cell _ ->
231+ Nothing
232+ )
156233
157234
158−{-| Extracts a 64-bit `Float`.
235+{-| Extracts a 64-bit `Float` at the given location.
159236-}
160−float64 : Deconstructor Float
161−float64 x =
162− case x of
163− Atom bs ->
164− BD.decode (BD.float64 LE) bs
165−
166− Cell _ ->
167− Nothing
237+float64 : Deconstructor (Float -> a) a
238+float64 =
239+ Deconstructor
240+ (\x f ->
241+ case x of
242+ Atom bs ->
243+ BD.decode (BD.float64 LE) bs
244+ |> Maybe.map f
245+
246+ Cell _ ->
247+ Nothing
248+ )
168249
169250
170−{-| Extracts the raw `Byte`s of an `Atom`.
251+{-| Extracts the raw `Byte`s of an `Atom` at the current location.
171252-}
172−bytes : Deconstructor Bytes
173−bytes n =
174− case n of
175− Atom bs ->
176− Just bs
253+bytes : Deconstructor (Bytes -> a) a
254+bytes =
255+ Deconstructor
256+ (\n f ->
257+ case n of
258+ Atom bs ->
259+ f bs |> Just
177260
178− Cell _ ->
179− Nothing
261+ Cell _ ->
262+ Nothing
263+ )
180264
181265
182−{-| Asserts the the `Atom` should be exactly `sig` (`~`).
266+{-| Asserts the the `Atom` at the current position should be exactly `sig` (`~`).
183267-}
184−sig : Deconstructor ()
185−sig n =
186− case n of
187− Atom b ->
188− if (Bytes.Extra.toByteValues b |> List.filter (\x -> x /= 0)) == [] then
189− Just ()
268+sig : Deconstructor a a
269+sig =
270+ Deconstructor
271+ (\n a ->
272+ case n of
273+ Atom b ->
274+ if (Bytes.Extra.toByteValues b |> List.filter (\x -> x /= 0)) == [] then
275+ Just a
190276
191− else
192− Nothing
277+ else
278+ Nothing
193279
194− Cell _ ->
195− Nothing
280+ Cell _ ->
281+ Nothing
282+ )
196283
197284
198−{-| Extracts a sig-terminated list of arbitrary elements.
285+{-| Extracts a sig-terminated list of arbitrary elements at the current position.
199286
200287The first argument is a `Deconstructor` of the elements of the list.
201288
202289-}
203−list : Deconstructor a -> Deconstructor (List a)
204−list f n =
205− let
206− go n_ =
207− case n_ of
208− Atom _ ->
209− Just []
290+list : Deconstructor (a -> a) a -> Deconstructor (List a -> b) b
291+list (Deconstructor f) =
292+ Deconstructor
293+ (\n g ->
294+ let
295+ go n_ =
296+ case n_ of
297+ Atom _ ->
298+ Just []
210299
211− Cell ( el, tail ) ->
212− Maybe.map2 (\a b -> a :: b) (f el) (go tail)
213− in
214− go n
300+ Cell ( el, tail ) ->
301+ Maybe.map2 (\a b -> a :: b) (f el identity) (go tail)
302+ in
303+ go n |> Maybe.map g
304+ )
215305
216306
217−alt : Deconstructor a -> Deconstructor a -> Deconstructor a
218−alt f g n =
219− case f n of
220− Just x ->
221− Just x
307+alt : Deconstructor a b -> Deconstructor a b -> Deconstructor a b
308+alt (Deconstructor f) (Deconstructor g) =
309+ Deconstructor
310+ (\n a ->
311+ case f n a of
312+ Just x ->
313+ Just x
222314
223− Nothing ->
224− g n
315+ Nothing ->
316+ g n a
317+ )
225318
226319
227320{-| Try to execute all of the `Deconstructor`s in order until one succeeds.
@@ -229,150 +322,64 @@ alt f g n =
229322This is especially useful for deconstructing head-tagged unions from Hoon.
230323
231324-}
232−oneOf : List (Deconstructor a) -> Deconstructor a
325+oneOf : List (Deconstructor a b) -> Deconstructor a b
233326oneOf l =
234327 case l of
235328 [] ->
236− always Nothing
329+ Deconstructor (\_ _ -> Nothing)
237330
238331 x :: xs ->
239332 alt x (oneOf xs)
240333
241334
242−{-| Ignore any value.
243−
244−This is useful when you have a value you don't care about. `ignore` allows you to just skip the value.
245−
246−-}
247−ignore : Deconstructor ()
248−ignore =
249− always (Just ())
250−
251−
252−{-| Extracts a [`Cell`](https://developers.urbit.org/reference/glossary/cell) (pair) of two arbitrary values.
253−
254−Accepts two arbitrary `Deconstructor`s that form a Cell.
255−
256−-}
257−cell : Deconstructor a -> Deconstructor b -> Deconstructor ( a, b )
258−cell l r noun =
259− case noun of
260− Cell ( lhs, rhs ) ->
261− l lhs |> Maybe.andThen (\a -> r rhs |> Maybe.map (\b -> ( a, b )))
262−
263− Atom _ ->
264− Nothing
265−
266−
267−{-| Maps (applies) a function to all of the values deconstructed.
268−
269−This is useful when you want to create a data type with extracted values as fields.
270−
271−-}
272−lazy : (() -> Deconstructor a) -> Deconstructor a
273−lazy f noun =
274− f () noun
335+{-| Extract the raw `Noun` at the current position.
275336
337+Always succeeds.
276338
277−{-| Maps over the result of the deconstructor.
278339-}
279−map : (a -> b) -> Deconstructor a -> Deconstructor b
280−map g f noun =
281− f noun |> Maybe.map g
282−
340+tar : Deconstructor (Noun -> a) a
341+tar =
342+ Deconstructor (\noun f -> Just (f noun))
283343
284−{-| Extracts a `cord`.
285−-}
286−cord : Deconstructor String
287−cord x =
288− case x of
289− Atom bs ->
290− BD.decode (BD.string (Bytes.width bs)) bs
291344
292− Cell _ ->
293− Nothing
345+{-| Ignore any value at the current position.
294346
347+This is useful when you have a value you don't care about. `ignore` allows you to just skip the value.
295348
296−{-| Extracts a `tape`.
297349-}
298−tape : Deconstructor String
299−tape =
300− list cord |> map String.concat
350+ignore : Deconstructor a a
351+ignore =
352+ Deconstructor (\_ f -> Just f)
301353
302354
303−{-| Extracts a 32-bit unsigned `Int`.
355+{-| Extracts a [`Cell`](https://developers.urbit.org/reference/glossary/cell) (pair) of two arbitrary values.
304356
305−If the `Atom` is larger than 32 bits the the behaviour is undefined.
357+Accepts two arbitrary `Deconstructor`s that form a Cell.
306358
307359-}
308−int : Deconstructor Int
309−int x =
310− case x of
311− Atom bs ->
312− case Bytes.width bs of
313− 1 ->
314− BD.decode BD.unsignedInt8 bs
315−
316− 2 ->
317− BD.decode (BD.unsignedInt16 LE) bs
318−
319− 3 ->
320− BD.decode (BD.unsignedInt32 LE) (BE.encode (BE.sequence [ BE.bytes bs, BE.unsignedInt8 0 ]))
321−
322− 4 ->
323− BD.decode (BD.unsignedInt32 LE) bs
360+cell : Deconstructor a b -> Deconstructor b c -> Deconstructor a c
361+cell (Deconstructor l) (Deconstructor r) =
362+ Deconstructor
363+ (\noun a ->
364+ case noun of
365+ Cell ( lhs, rhs ) ->
366+ l lhs a |> Maybe.andThen (\b -> r rhs b)
324367
325− _ ->
368+ Atom _ ->
326369 Nothing
370+ )
327371
328− Cell _ ->
329− Nothing
330−
331−
332−{-| Extract the raw `Noun`.
333−
334−Always succeeds.
335372
336−-}
337−tar : Deconstructor Noun
338−tar =
339− Just
373+{-| Maps (applies) a function to all of the values deconstructed.
340374
375+This is useful when you want to create a data type with extracted values as fields.
341376
342−{-| Debug a deconstructor.
343−If the deconstructor from the second argument fails then the failed nock will be printed to the console.
344377-}
345−debug : (String -> String) -> Deconstructor a -> Deconstructor a
346−debug log f noun =
347− case f noun of
348− Just x ->
349− Just x
378+map : a -> Deconstructor a b -> Deconstructor (b -> c) c
379+map a (Deconstructor f) =
380+ Deconstructor (\noun g -> f noun a |> Maybe.map g)
350381
351− Nothing ->
352− let
353− _ =
354− log (prettyNoun noun)
355− in
356− Nothing
357−
358−
359−prettyNoun : Noun -> String
360−prettyNoun noun =
361− let
362− go isRhs n =
363− case n of
364− Atom a ->
365− if isSig a then
366− "~"
367382
368− else
369− "@"
370−
371− Cell ( lhs, rhs ) ->
372− if isRhs then
373− go False lhs ++ " " ++ go True rhs
374−
375− else
376− "[" ++ go False lhs ++ " " ++ go True rhs ++ "]"
377− in
378− go False noun
383+fmap : (a -> b) -> Deconstructor (a -> c) c -> Deconstructor (b -> c) c
384+fmap f (Deconstructor g) =
385+ Deconstructor (\noun h -> g noun (f >> h))
src/Ur/NounDiff.elmdeleted−115
@@ -1,115 +0,0 @@
1−module Ur.NounDiff exposing (Patch, apply, deconstructPatch)
2−
3−import Bytes.Extra
4−import Dict exposing (Dict)
5−import Ur.Deconstructor as D
6−import Ur.Types exposing (..)
7−
8−
9−type Patch
10− = PatchCell Patch Patch
11− | Diff DelDiff InsDiff
12−
13−
14−deconstructPatch : () -> D.Deconstructor Patch
15−deconstructPatch () =
16− D.oneOf
17− [ D.cell (D.const D.cord "cell")
18− (D.cell
19− (D.lazy deconstructPatch)
20− (D.lazy deconstructPatch)
21− )
22− |> D.map (\( (), ( a, b ) ) -> PatchCell a b)
23− , D.cell (D.const D.cord "diff") (D.cell (D.lazy deconstructDel) (D.lazy deconstructIns))
24− |> D.map (\( (), ( a, b ) ) -> Diff a b)
25− ]
26−
27−
28−apply : Patch -> Noun -> Noun
29−apply patch noun =
30− case ( patch, noun ) of
31− ( PatchCell lhs rhs, Cell ( lhs_, rhs_ ) ) ->
32− Cell ( apply lhs lhs_, apply rhs rhs_ )
33−
34− ( Diff delDiff insDiff, _ ) ->
35− ins insDiff (del delDiff noun)
36−
37− _ ->
38− noun
39−
40−
41−del : DelDiff -> Noun -> Dict Int Noun
42−del diff noun =
43− let
44− go : DelDiff -> Noun -> Dict Int Noun -> Dict Int Noun
45− go diff_ noun_ dict =
46− case ( diff_, noun_ ) of
47− ( Ignore, _ ) ->
48− dict
49−
50− ( DelCell lhsDiff rhsDiff, Cell ( lhs, rhs ) ) ->
51− go lhsDiff lhs (go rhsDiff rhs dict)
52−
53− ( DelHole hole, _ ) ->
54− -- There should be a continuity check here.
55− -- Check that the noun_ is equal to whatever the hole maps to in dict.
56− -- I don't include it for speed and laziness reasons.
57− Dict.insert hole noun_ dict
58−
59− _ ->
60− dict
61− in
62− go diff noun Dict.empty
63−
64−
65−ins : InsDiff -> Dict Int Noun -> Noun
66−ins diff dict =
67− case diff of
68− InsAtom a ->
69− Atom a
70−
71− InsHole hole ->
72− Dict.get hole dict |> Maybe.withDefault (Atom Bytes.Extra.empty)
73−
74− InsCell lhs rhs ->
75− Cell ( ins lhs dict, ins rhs dict )
76−
77−
78−type DelDiff
79− = Ignore
80− | DelHole Int
81− | DelCell DelDiff DelDiff
82−
83−
84−deconstructDel : () -> D.Deconstructor DelDiff
85−deconstructDel () =
86− D.oneOf
87− [ D.cell (D.const D.cord "ignore") D.ignore |> D.map (\( (), () ) -> Ignore)
88− , D.cell (D.const D.cord "hole") D.int |> D.map (\( (), x ) -> DelHole x)
89− , D.cell (D.const D.cord "cell")
90− (D.cell
91− (D.lazy deconstructDel)
92− (D.lazy deconstructDel)
93− )
94− |> D.map (\( (), ( lhs, rhs ) ) -> DelCell lhs rhs)
95− ]
96−
97−
98−type InsDiff
99− = InsAtom Atom
100− | InsHole Int
101− | InsCell InsDiff InsDiff
102−
103−
104−deconstructIns : () -> D.Deconstructor InsDiff
105−deconstructIns () =
106− D.oneOf
107− [ D.cell (D.const D.cord "hole") D.int |> D.map (\( (), x ) -> InsHole x)
108− , D.cell (D.const D.cord "atom") D.bytes |> D.map (\( (), bs ) -> InsAtom bs)
109− , D.cell (D.const D.cord "cell")
110− (D.cell
111− (D.lazy deconstructIns)
112− (D.lazy deconstructIns)
113− )
114− |> D.map (\( (), ( a, b ) ) -> InsCell a b)
115− ]
src/Ur/Phonemic.elm+1−1
@@ -13,7 +13,7 @@ import Urbit.Encoding.Atom exposing (toBigInt)
1313import Urbit.Encoding.Phonemic exposing (..)
1414
1515
16−{-| Converts a ship name like `~zod` into an `Atom`.
16+{-| Converts a ship name like `~zod` into an Atom.
1717-}
1818fromString : Ship -> Atom
1919fromString s =
src/Ur/Requests.elm+1−1
@@ -98,7 +98,7 @@ toNoun eventId req =
9898 C.cell (C.cord app) (C.listOf C.cord path)
9999
100100 Unsubscribe subId ->
101− C.cell (C.cord "unsubscribe") <|
101+ C.cell (C.cord "usubscribe") <|
102102 C.cell (C.int eventId) (C.int subId)
103103
104104 Poke { ship, agent, mark, noun } ->
src/Ur/Run.elm+23−80
@@ -18,7 +18,6 @@ import Ur.Cmd
1818import Ur.Cmd.Internal
1919import Ur.Constructor as C
2020import Ur.Deconstructor as D
21−import Ur.NounDiff exposing (Patch, deconstructPatch)
2221import Ur.Requests exposing (..)
2322import Ur.Sub
2423import Ur.Sub.Internal
@@ -31,9 +30,8 @@ type alias SubDict msg =
3130 Dict
3231 -- (ship, agent, path)
3332 ( String, String, List String )
34− { deconstructor : D.Deconstructor msg
33+ { deconstructor : D.Deconstructor (msg -> msg) msg
3534 , number : Int
36− , sink : Bool
3735 }
3836
3937
@@ -51,7 +49,6 @@ type alias Model app msg =
5149 , eventId : Int
5250 , flags : Flags
5351 , requestsToRetry : List UrbitRequest
54− , sinks : Dict Int Noun
5552 }
5653
5754
@@ -174,11 +171,12 @@ update inp msg model =
174171 ( appModel, appCmds ) =
175172 inp.update msg_ model.app
176173
174+ -- { subscriptions, eventId, subscriptionRequests, subscriptionIntMapping } =
177175 subsResult =
178176 processUrSubs
179177 model.eventId
180178 model.subscriptions
181− (inp.urbitSubscriptions appModel |> (\(Ur.Sub.Internal.Sub x) -> x))
179+ (inp.urbitSubscriptions model.app |> (\(Ur.Sub.Internal.Sub x) -> x))
182180
183181 ( eventId_, cmds, urReqs ) =
184182 processCmd subsResult.eventId appCmds
@@ -211,10 +209,12 @@ update inp msg model =
211209 Ok string ->
212210 case
213211 D.runBytes
214− (D.cell D.int (D.cell D.cord D.tar))
212+ (D.cell D.int (D.cell D.cord D.tar)
213+ |> D.map (\a b c -> ( a, b, c ))
214+ )
215215 (Ur.Uw.decode string)
216216 of
217− Just ( messageId, ( messageType, rest ) ) ->
217+ Just ( messageId, messageType, rest ) ->
218218 let
219219 ( eventId, ackReqs ) =
220220 tag model.eventId [ Ack messageId ]
@@ -244,51 +244,14 @@ update inp msg model =
244244 Dict.get messageId model.subscriptionIntMapping
245245 |> Maybe.andThen (\key -> Dict.get key model.subscriptions)
246246 of
247− Just { deconstructor, sink } ->
248− if sink then
249− case D.run (D.cell D.ignore (D.cell D.ignore deconstructSink) |> D.map (\( (), ( (), s ) ) -> s)) rest of
250− Just (Flush noun) ->
251− ( { model | sinks = Dict.insert messageId noun model.sinks }
252− , case D.run deconstructor noun of
253− Just subMsg ->
254− pureCmd (AppMsg subMsg)
255−
256− -- Got garbage
257− Nothing ->
258− Cmd.none
259− )
260−
261− Just (Drain patch) ->
262− case Dict.get messageId model.sinks of
263− Just oldNoun ->
264− let
265− newNoun =
266− Ur.NounDiff.apply patch oldNoun
267− in
268− ( { model | sinks = Dict.insert messageId newNoun model.sinks }
269− , case D.run deconstructor newNoun of
270− Just subMsg ->
271− pureCmd (AppMsg subMsg)
272−
273− Nothing ->
274− Cmd.none
275− )
276−
277− Nothing ->
278− ( model, Cmd.none )
279−
280− -- Got garbage
281− Nothing ->
282− ( model, Cmd.none )
283−
284− else
285− case D.run (D.cell D.ignore (D.cell D.ignore deconstructor) |> D.map (\( (), ( (), m ) ) -> m)) rest of
286− Just subMsg ->
287− ( model_, pureCmd (AppMsg subMsg) )
288−
289− -- Got gargbage
290− Nothing ->
291− ( model_, ackCmd )
247+ Just { deconstructor } ->
248+ case D.run (D.cell D.ignore (D.cell D.ignore deconstructor)) rest of
249+ Just subMsg ->
250+ ( model_, pureCmd (AppMsg subMsg) )
251+
252+ -- Got gargbage
253+ Nothing ->
254+ ( model_, ackCmd )
292255
293256 -- Got a fact for a subscription we do not hold
294257 Nothing ->
@@ -313,11 +276,11 @@ update inp msg model =
313276 NeedsActivation ->
314277 let
315278 ( eventId, reqs ) =
316− [ Poke { ship = "", agent = "hood", mark = "helm-hi", noun = C.cord "Opening airlock!" } ]
279+ [ Poke { ship = "~zod", agent = "hood", mark = "helm-hi", noun = C.cord "Opening airlock!" } ]
317280 |> tag model.eventId
318281 in
319282 ( { model | eventId = eventId }
320− , send { url = url, requests = reqs, success = OpenConnection, error = Noop }
283+ , send { url = url, requests = reqs, success = OpenConnection, error = NeedsActivation }
321284 )
322285
323286 Noop ->
@@ -344,19 +307,6 @@ update inp msg model =
344307 )
345308
346309
347−type Sink
348− = Flush Noun
349− | Drain Patch
350−
351−
352−deconstructSink : D.Deconstructor Sink
353−deconstructSink =
354− D.oneOf
355− [ D.cell (D.const D.cord "flush") D.tar |> D.map (\( (), n ) -> Flush n)
356− , D.cell (D.const D.cord "drain") (D.lazy deconstructPatch) |> D.map (\( (), patch ) -> Drain patch)
357− ]
358−
359−
360310processCmd : EventId -> Ur.Cmd.Cmd msg -> ( EventId, Cmd (Msg msg), List ( EventId, UrbitRequest ) )
361311processCmd eventId urCmds =
362312 let
@@ -386,10 +336,10 @@ pureCmd msg =
386336
387337processUrSubs :
388338 EventId
389− -> Dict ( Ship, Agent, Path ) { deconstructor : d, number : EventId, sink : Bool }
390− -> Dict ( Ship, Agent, Path ) { deconstructor : d, sink : Bool }
339+ -> Dict ( Ship, Agent, Path ) { deconstructor : d, number : EventId }
340+ -> Dict ( Ship, Agent, Path ) d
391341 ->
392− { subscriptions : Dict ( Ship, Agent, Path ) { deconstructor : d, number : EventId, sink : Bool }
342+ { subscriptions : Dict ( Ship, Agent, Path ) { deconstructor : d, number : EventId }
393343 , eventId : EventId
394344 , subscriptionRequests : List ( EventId, UrbitRequest )
395345 , subscriptionIntMapping : Dict EventId ( Ship, Agent, Path )
@@ -398,7 +348,7 @@ processUrSubs eventId existingSubscriptions urbitSubs_ =
398348 let
399349 urbitSubs =
400350 urbitSubs_
401− |> Dict.map (\_ { deconstructor, sink } -> { deconstructor = deconstructor, sink = sink })
351+ |> Dict.map (\_ deconstructor -> { deconstructor = deconstructor })
402352
403353 ( eventId_, newSubscriptionActions ) =
404354 Dict.diff urbitSubs existingSubscriptions
@@ -421,11 +371,10 @@ processUrSubs eventId existingSubscriptions urbitSubs_ =
421371 newSubscriptions =
422372 Dict.merge
423373 (\_ _ x -> x)
424− (\key number { deconstructor, sink } ->
374+ (\key number { deconstructor } ->
425375 Dict.insert key
426376 { deconstructor = deconstructor
427377 , number = number
428− , sink = sink
429378 }
430379 )
431380 (\_ _ x -> x)
@@ -468,7 +417,6 @@ init inp ( app, appCmds ) flags =
468417 inp.urbitUrl app ++ "/~/channel/" ++ flags.uid
469418 in
470419 ( { subscriptions = subsResult.subscriptions
471− , sinks = Dict.empty
472420 , subscriptionIntMapping = subsResult.subscriptionIntMapping
473421 , app = app
474422 , connected = False
@@ -491,7 +439,7 @@ init inp ( app, appCmds ) flags =
491439
492440subscriptions :
493441 { a | subscriptions : b -> Sub msg, onEventSourceMsg : (JD.Value -> Msg c) -> Sub (Msg msg) }
494− -> { d | app : b, requestsToRetry : List e, connected : Bool }
442+ -> { d | app : b, requestsToRetry : List e }
495443 -> Sub (Msg msg)
496444subscriptions inp model =
497445 Sub.batch
@@ -502,9 +450,4 @@ subscriptions inp model =
502450
503451 else
504452 Time.every 1000 (always RetryRequests)
505− , if not model.connected then
506− Time.every 10000 (always NeedsActivation)
507−
508− else
509− Sub.none
510453 ]
src/Ur/Sub.elm+6−21
@@ -1,8 +1,8 @@
1−module Ur.Sub exposing (Sub, subscribe, none, batch, sink)
1+module Ur.Sub exposing (Sub, subscribe, none, batch)
22
3−{-| This module is conceptually similar to `Platform.Sub`, but allows you to subscribe to Urbit channels.
3+{-| This module is conceptually similar to `Platform.Sub`, but also you to subscribe to Urbit channels.
44
5−@docs Sub, subscribe, none, batch, sink
5+@docs Sub, subscribe, none, batch
66
77-}
88
@@ -11,7 +11,7 @@ import Ur.Deconstructor as D
1111import Ur.Sub.Internal
1212
1313
14−{-| Like `Sub` from `Platform.Sub` but for Urbit subscriptions.
14+{-| Like `Sub` from `Platform.Sub`, but for Urbit subscriptions.
1515-}
1616type alias Sub msg =
1717 Ur.Sub.Internal.Sub msg
@@ -27,24 +27,9 @@ type alias Sub msg =
2727 }
2828
2929-}
30−subscribe : { ship : String, app : String, path : List String, deconstructor : D.Deconstructor msg } -> Sub msg
30+subscribe : { ship : String, app : String, path : List String, deconstructor : D.Deconstructor (msg -> msg) msg } -> Sub msg
3131subscribe { ship, app, path, deconstructor } =
32− Dict.singleton ( ship, app, path )
33− { deconstructor = deconstructor
34− , sink = False
35− }
36− |> Ur.Sub.Internal.Sub
37−
38−
39−{-| Creates a %sink subscription.
40−-}
41−sink : { ship : String, app : String, path : List String, deconstructor : D.Deconstructor msg } -> Sub msg
42−sink { ship, app, path, deconstructor } =
43− Dict.singleton ( ship, app, path )
44− { deconstructor = deconstructor
45− , sink = True
46− }
47− |> Ur.Sub.Internal.Sub
32+ Dict.singleton ( ship, app, path ) deconstructor |> Ur.Sub.Internal.Sub
4833
4934
5035{-| A subscription that does exactly nothing. (Does not subscribe to anything)
src/Ur/Sub/Internal.elm+1−3
@@ -10,7 +10,5 @@ type Sub msg
1010 (Dict
1111 -- key is (ship, app, path)
1212 ( Ship, Agent, Path )
13− { deconstructor : D.Deconstructor msg
14− , sink : Bool
15− }
13+ (D.Deconstructor (msg -> msg) msg)
1614 )
src/Ur/Uw.elm+8−8
@@ -1,6 +1,6 @@
11module Ur.Uw exposing (decode, encode)
22
3−{-| This module works with Urbit base-64 encoded strings aka `@uw`.
3+{-| This module works with Urbit base-64 encoded strings.
44
55@docs decode, encode
66
@@ -29,24 +29,24 @@ decode string =
2929 -- 0w
3030 |> List.drop 2
3131
32− go : List Char -> List Int -> BW.BitWriter -> BW.BitWriter
33− go cs append writer =
32+ go : List Char -> BW.BitWriter -> BW.BitWriter
33+ go cs writer =
3434 case cs of
3535 [] ->
36− BW.bits append writer
36+ writer
3737
3838 '.' :: rest ->
39− go rest append writer
39+ go rest writer
4040
4141 c :: rest ->
4242 case Dict.get c charToBits of
4343 Just bits ->
44− go rest (bits ++ append) writer
44+ go rest writer |> BW.bits bits
4545
4646 Nothing ->
47− go rest [] writer
47+ go rest writer
4848 in
49− BW.run (go chars [] BW.empty)
49+ BW.run (go chars BW.empty)
5050
5151
5252{-| -}
tests/Test/Urbit.elm+11−11
@@ -77,7 +77,7 @@ tests =
7777 Expect.equal
7878 (Just ( 1, 2 ))
7979 (D.runBytes
80− (D.cell D.int D.int)
80+ (D.cell D.int D.int |> D.map Tuple.pair)
8181 (Bytes.fromByteValues [ 0x31, 0x12 ])
8282 )
8383 )
@@ -96,7 +96,7 @@ tests =
9696 Expect.equal
9797 (Just ( 4, [ 1, 2, 3 ] ))
9898 (D.runBytes
99− (D.cell D.int (D.list D.int))
99+ (D.cell D.int (D.list D.int) |> D.map Tuple.pair)
100100 (Bytes.fromByteValues [ 0x61, 0xC6, 0x21, 0x43, 0x0B ])
101101 )
102102 )
@@ -105,7 +105,7 @@ tests =
105105 Expect.equal
106106 (Just ( 8, 11 ))
107107 (D.runBytes
108− (D.cell D.float32 D.float32)
108+ (D.cell D.float32 D.float32 |> D.map Tuple.pair)
109109 (Bytes.fromByteValues [ 0x01, 0x1F, 0x00, 0x00, 0x20, 0x08, 0x7C, 0x00, 0x00, 0x98, 0x20 ])
110110 )
111111 )
@@ -114,7 +114,7 @@ tests =
114114 Expect.equal
115115 (Just ( 8, "hi" ))
116116 (D.runBytes
117− (D.cell D.int D.cord)
117+ (D.cell D.int D.cord |> D.map Tuple.pair)
118118 (Bytes.fromByteValues [ 0x41, 0x10, 0x3C, 0x5A, 0x1A ])
119119 )
120120 )
@@ -123,7 +123,7 @@ tests =
123123 Expect.equal
124124 (Just ( 8, "hi" ))
125125 (D.runBytes
126− (D.cell D.int D.tape)
126+ (D.cell D.int D.tape |> D.map Tuple.pair)
127127 (Bytes.fromByteValues [ 0x41, 0x30, 0x38, 0x3A, 0x78, 0x5A ])
128128 )
129129 )
@@ -134,8 +134,8 @@ tests =
134134 (Just "hi")
135135 (D.runBytes
136136 (D.oneOf
137− [ D.cell (D.const D.cord "tape") D.tape |> D.map (\((), t) -> t)
138− , D.cell (D.const D.cord "cord") D.cord |> D.map (\((), c) -> c)
137+ [ D.cell (D.const D.cord "tape") D.tape
138+ , D.cell (D.const D.cord "cord") D.cord
139139 ]
140140 )
141141 (Bytes.fromByteValues [ 0x01, 0x9F, 0x2E, 0x0C, 0xAE, 0x1C, 0x1C, 0x1D, 0x3C, 0x2D ])
@@ -147,8 +147,8 @@ tests =
147147 (Just "hi")
148148 (D.runBytes
149149 (D.oneOf
150− [ D.cell (D.const D.cord "tape") D.tape |> D.map (\((), t) -> t)
151− , D.cell (D.const D.cord "cord") D.cord |> D.map (\((), c) -> c)
150+ [ D.cell (D.const D.cord "tape") D.tape
151+ , D.cell (D.const D.cord "cord") D.cord
152152 ]
153153 )
154154 (Bytes.fromByteValues [ 0x01, 0x7F, 0xEC, 0x4D, 0x8E, 0x0C, 0x1E, 0x2D, 0x0D ])
@@ -160,7 +160,7 @@ tests =
160160 Expect.equal
161161 (Just ( 8, -8 ))
162162 (D.runBytes
163− (D.cell D.signedInt D.signedInt)
163+ (D.cell D.signedInt D.signedInt |> D.map Tuple.pair)
164164 (Bytes.fromByteValues [ 0xC1, 0x20, 0xE4, 0x01 ])
165165 )
166166 )
@@ -190,7 +190,7 @@ tests =
190190 (\( f, i, ui ) ->
191191 Expect.equal (Just ( f, i, ui ))
192192 (D.run
193− (D.cell D.float64 (D.cell D.signedInt D.int) |> D.map (\(a, (b, c)) -> ( a, b, c )))
193+ (D.cell D.float64 (D.cell D.signedInt D.int) |> D.map (\a b c -> ( a, b, c )))
194194 (C.cell (C.float64 f) (C.cell (C.signedInt i) (C.int ui)))
195195 )
196196 )