[elm-discuss] Re: Record update syntax

2016-08-13 Thread Robin Heggelund Hansen
All I really want is:

```elm
{ model.something |  more = 42 }
```

søndag 14. august 2016 02.49.07 UTC+2 skrev OvermindDL1 følgende:
>
> Just a passing idea to perhaps help give ideas for better methods:
>
>
> Updating a nested record is a bit convoluted as something like:
> ```elm
> let
>   something = model.something
> in
>   { model | something = { something | more = 42 } }
> ```
> Excepting the let/in part because Elm does not support an expression as 
> the first argument (`model` and `something` in these cases) for 
> I-have-no-clue-reason, and another language I work often in is Elixir, its 
> syntax for the above would be similar:
> ```elixir
>   %{ model | something: %{ model.something | more: 42 } }
> ```
>
> However, that is painful, so Elixir has a couple of helper functions that 
> simplify that kind of work, let me demonstrate, this does the same as the 
> above:
> ```elixir
>   put_in models, [:something, :more], 42
> ```
> And you can go arbitrarily deep and it returns a new model with the path 
> altered to the given value as necessary.  Elixir also has lispy macros so 
> you can also use the above function via:
> ```elixir
>   put_in models.something.more, 42
> ```
> Basically using 'read' syntax to specify the path, but it gets expanded to 
> the above at compile-time.  It also supports not only records but also maps 
> (dicts in elm), lists (also lists in elm) and anything else that follows 
> the Access protocol (a set of functions of certain types to do basic 
> functions), but those are the default.
>
> It has extra features like this, say `model.something` is a `List Int` in 
> elm parlance:
> ```elixir
> put_in model, [:something, Access.all], 42
> ```
> This will set any and all values in the list at model.something to 42, not 
> terribly useful, however it has a lot more functions as well, such as (I 
> want to use more 'elmy' syntax, so I will now use things like `.something` 
> instead of `:something` and no commas between arguments, only in tuples and 
> lists and such):
> ```elixir
> -- Where model = { something : Dict String (List Int) }
> ( oldValue, newModel ) = get_and_update_in model [ .something, "joe", 
> Access.at(0) ] (\oldValue -> let oldValue = Maybe.withDefault 0 in ( 
> oldValue, Just (oldValue+1) ))
> ```
> This will update a value in and let you return a value (anything you wish) 
> within a tuple.  This one will access `Dict.get "joe" model.something` and 
> get the returned list, accessing the first element (`at` for lists, `elem` 
> for a tuple index starting at 0 as well), and the called passed in function 
> returns a tuple where the first element is the first element of the 
> returned tuple and the second element is what the thing at the path will be 
> updated to, so this case will return the `oldValue+1` if it existed, if it 
> did not then it returns 1 due to the `withDefault 0`.
>
> More functions it adds are:
> ```elixir
> -- Where model = { something : Dict String (List Int) }
> value = get_in model [ .something, "joe", Access.at(2) ] -- Returns the 
> value at the path
>
> values = get_in model [ .something, Access.all, Access.at(2) ] -- Returns 
> all of the values 2nd values in the lists in all the values of the 
> dictionary as a list if they exist, else they are skipped
>
> pop_in model [ .something, Access.all, Access.at(2) ] -- Removes the 
> element in the list at position 2 in all the dictionary values if it 
> exists, if it does not exist then it skips it
>
> update_in model [ .something, Access.all, Access.at(2) ] (\oldValue -> 
> Just (( oldValue |> Maybe.withDefault 0 ) + 4)) -- Updates a value(s) 
> in-place
> ```
> Along with macro's for the read-format pathing, which is not needed here.
>
> The keylist (the `[ .something, Access.all, Access.at(2) ]` in the last 
> example) can also take functions, whatever they return (empty list, 
> single-element list, multiple-element list, etc...) will be what is used 
> and what is set back.
>
>
> *Thus*, what would be thought of Elm adding in functions like these 
> (HKT's might be needed, not thought through the implementation yet, only 
> the API):
> ```
> type Access
>   = All
>   | At Int
>   | Elem Int
>   | Key recordKeyType {- Whatever recordKeyType might be as an indicator 
> for a key on a record -}
>   | DictKey dictKeyType
>   | Fn (EnumerableType -> EnumerableType) {- This is why I think HKT's 
> might be needed, or special caseing in the compiler -}
>
> -- You'd need some kind of EnumerableType as well, no doubt opaque or 
> something, or need HKT's, probably need HKT's in general, Elm really badly 
> needs HKT's...
>
> {-| Get a value calculated from the old value and set a new value 
> simultaneously -}
> getAndUpdateIn
>   : List Access
>   -> (Maybe valueType -> ( retValue, Maybe valueType ))
>   -> EnumerableType
>   -> ( List retValue, EnumerableType )
>
>
> {-| Gets a value from an access path -}
> getIn
>   : List Access
>   -> EnumerableType
>   -> List retValue
>
>
> 

[elm-discuss] Re: More thorough side-effect isolation

2016-08-13 Thread Kasey Speakman
So, I made a Gist 
 of the 
helper stuff which splits Facts and Acts. I call the helper Factor... (Fact 
or Act ~=> Factor). There is a subsequent comment with an example program 
explaining the helper's usage.

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[elm-discuss] Record update syntax

2016-08-13 Thread OvermindDL1
Just a passing idea to perhaps help give ideas for better methods:


Updating a nested record is a bit convoluted as something like:
```elm
let
  something = model.something
in
  { model | something = { something | more = 42 } }
```
Excepting the let/in part because Elm does not support an expression as the 
first argument (`model` and `something` in these cases) for 
I-have-no-clue-reason, and another language I work often in is Elixir, its 
syntax for the above would be similar:
```elixir
  %{ model | something: %{ model.something | more: 42 } }
```

However, that is painful, so Elixir has a couple of helper functions that 
simplify that kind of work, let me demonstrate, this does the same as the 
above:
```elixir
  put_in models, [:something, :more], 42
```
And you can go arbitrarily deep and it returns a new model with the path 
altered to the given value as necessary.  Elixir also has lispy macros so 
you can also use the above function via:
```elixir
  put_in models.something.more, 42
```
Basically using 'read' syntax to specify the path, but it gets expanded to 
the above at compile-time.  It also supports not only records but also maps 
(dicts in elm), lists (also lists in elm) and anything else that follows 
the Access protocol (a set of functions of certain types to do basic 
functions), but those are the default.

It has extra features like this, say `model.something` is a `List Int` in 
elm parlance:
```elixir
put_in model, [:something, Access.all], 42
```
This will set any and all values in the list at model.something to 42, not 
terribly useful, however it has a lot more functions as well, such as (I 
want to use more 'elmy' syntax, so I will now use things like `.something` 
instead of `:something` and no commas between arguments, only in tuples and 
lists and such):
```elixir
-- Where model = { something : Dict String (List Int) }
( oldValue, newModel ) = get_and_update_in model [ .something, "joe", 
Access.at(0) ] (\oldValue -> let oldValue = Maybe.withDefault 0 in ( 
oldValue, Just (oldValue+1) ))
```
This will update a value in and let you return a value (anything you wish) 
within a tuple.  This one will access `Dict.get "joe" model.something` and 
get the returned list, accessing the first element (`at` for lists, `elem` 
for a tuple index starting at 0 as well), and the called passed in function 
returns a tuple where the first element is the first element of the 
returned tuple and the second element is what the thing at the path will be 
updated to, so this case will return the `oldValue+1` if it existed, if it 
did not then it returns 1 due to the `withDefault 0`.

More functions it adds are:
```elixir
-- Where model = { something : Dict String (List Int) }
value = get_in model [ .something, "joe", Access.at(2) ] -- Returns the 
value at the path

values = get_in model [ .something, Access.all, Access.at(2) ] -- Returns 
all of the values 2nd values in the lists in all the values of the 
dictionary as a list if they exist, else they are skipped

pop_in model [ .something, Access.all, Access.at(2) ] -- Removes the 
element in the list at position 2 in all the dictionary values if it 
exists, if it does not exist then it skips it

update_in model [ .something, Access.all, Access.at(2) ] (\oldValue -> Just 
(( oldValue |> Maybe.withDefault 0 ) + 4)) -- Updates a value(s) in-place
```
Along with macro's for the read-format pathing, which is not needed here.

The keylist (the `[ .something, Access.all, Access.at(2) ]` in the last 
example) can also take functions, whatever they return (empty list, 
single-element list, multiple-element list, etc...) will be what is used 
and what is set back.


*Thus*, what would be thought of Elm adding in functions like these (HKT's 
might be needed, not thought through the implementation yet, only the API):
```
type Access
  = All
  | At Int
  | Elem Int
  | Key recordKeyType {- Whatever recordKeyType might be as an indicator 
for a key on a record -}
  | DictKey dictKeyType
  | Fn (EnumerableType -> EnumerableType) {- This is why I think HKT's 
might be needed, or special caseing in the compiler -}

-- You'd need some kind of EnumerableType as well, no doubt opaque or 
something, or need HKT's, probably need HKT's in general, Elm really badly 
needs HKT's...

{-| Get a value calculated from the old value and set a new value 
simultaneously -}
getAndUpdateIn
  : List Access
  -> (Maybe valueType -> ( retValue, Maybe valueType ))
  -> EnumerableType
  -> ( List retValue, EnumerableType )


{-| Gets a value from an access path -}
getIn
  : List Access
  -> EnumerableType
  -> List retValue


{-| Removes a value from a given path if possible, returning it if it 
exists -}
popIn
  : List Access
  -> EnumerableType
  -> ( List retValue, EnumerableType )


{-| Sets a value(s) at the given path -}
putIn
  : List Access
  -> newValue
  -> EnumerableType
  -> EnumerableType


{-| Updates a value in the path and returns the new modified object -}
updateIn
  : 

[elm-discuss] Re: How do I write an elm-check producer for a recursive data structure?

2016-08-13 Thread Max Goldstein
@John Yes, elm-check was deprecated earlier this will. You almost certainly 
have an old version of the elm-test shell utility; "elm test --version" 
should yield 0.17.1. If it doesn't,

npm uninstall -g elm-test
npm install -g elm-test

"elm test init" will create the directory *tests* which will contain a 
runner file Main.elm that you don't need to touch, and Tests.elm where you 
put your tests.

One of the big improvements over elm-check is that a fuzz test that fails 
many times still counts as one failing test. This wasn't possible using 
*evidenceToTest*.

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[elm-discuss] Re: Trying to create a nested components that calls a js interop port

2016-08-13 Thread Jonathan Duncan
Thank you for helping me find that.

I put the lift in a PlatformHelpers.elm file.  

Then I added a function to my JsInterop.State

which curries the lift function 

liftMe :
({ a | jsInterop : Model } -> Model -> { a | jsInterop : Model })
-> (Msg -> b)
-> Msg
-> { a | jsInterop : Model }
-> ( { a | jsInterop : Model }, Cmd b )
liftMe set fwd =
lift .jsInterop set fwd update


and I can call it from my outer component function like so.


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
JsInterop action ->
JsInterop.State.liftMe (\m x -> { m | jsInterop = x }) 
 JsInterop action model

It will make all my components take a dependency on PlatformHelpers but on 
the outer component!

It would've been even more elegant to forgo the setter lambda and be able 
to just pass the field we want to update like this
   JsInterop.State.liftMe .jsInterop  JsInterop action model


But I understand this is not possible in Elm
https://lexi-lambda.github.io/blog/2015/11/06/functionally-updating-record-types-in-elm/

I see that there is something called Focus but it looks like it would 
actually be longer than writing (\m x -> { m | jsInterop = x }) in the 
first place.  As I would have to write setters for each of fields which is 
what I am trying to get away from.

Jonathan


-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[elm-discuss] Re: Trying to create a nested components that calls a js interop port

2016-08-13 Thread OvermindDL1
`elm-mdl` I think calls it `lift`, but is the same pattern. It is the 
pattern that matters, not the name.  :-)

For example, look in the `elm-mdl` demo, it has a Primary message called 
'Mdl' (you could call it anything of course), and that 'Mdl' message is 
passed in to almost all of `elm-mdl`'s functions so that `elm-mdl` can 
return messages that work with the parent naturally that can then get 
passed back in.

And yes, the `elm-mdl` method requires that the model has a key that is 
named `mdl`, it is more limited, but you only ever have one so it is 
generally fine for this case.


On Saturday, August 13, 2016 at 10:44:06 AM UTC-6, Jonathan Duncan wrote:
>
> Thank you OvermindDL1,  that was helpful.
>
>
> I like your first idea of destructing the tuple.  That looks a lot better.
>
>
> I like how your second example looks, is so short and simple which is what 
> I was looking for. But I believe that it implies that the inner component 
> needs to know about the outer components' types. Right?
>
> I looked through https://github.com/debois/elm-mdl but didn't find an 
> example of a mapper.
>
> I only found in the 
> https://github.com/debois/elm-mdl/blob/66a1f2c10cb3850686eb610174710e9fcf176425/src/Material/Layout.elm
>  
> file
>
> but the f parameter isn't used anywhere.
>
> Let me know if you think of any other examples.  Thanks
>
> {-| Component update for Parts. 
> -}
> update' : (Msg -> msg) -> Msg -> Model -> Maybe (Model, Cmd msg)
> update' f action model = 
>

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[elm-discuss] Re: Trying to create a nested components that calls a js interop port

2016-08-13 Thread Jonathan Duncan
Thank you OvermindDL1,  that was helpful.


I like your first idea of destructing the tuple.  That looks a lot better.


I like how your second example looks, is so short and simple which is what 
I was looking for. But I believe that it implies that the inner component 
needs to know about the outer components' types. Right?

I looked through https://github.com/debois/elm-mdl but didn't find an 
example of a mapper.

I only found in 
the 
https://github.com/debois/elm-mdl/blob/66a1f2c10cb3850686eb610174710e9fcf176425/src/Material/Layout.elm
 
file

but the f parameter isn't used anywhere.

Let me know if you think of any other examples.  Thanks

{-| Component update for Parts. 
-}
update' : (Msg -> msg) -> Msg -> Model -> Maybe (Model, Cmd msg)
update' f action model = 

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[elm-discuss] Websocket.send return type?

2016-08-13 Thread Ben Burdette

I'm looking at the websockets example here:  
http://elm-lang.org/examples/websockets

According to the source 
(https://github.com/elm-lang/websocket/blob/1.0.1/src/WebSocket.elm), it 
looks like the type of Websocket.send is (String->String->Cmd msg), and in 
the update ftn of the websocket example, what's being returned is 
(Websocket.send  ).

That works out to have a type of "Cmd msg", where I assume msg is a lower 
case type variable.  What is the type of msg in (Cmd msg) which send 
returns?  Because its returned by the "update" function, it should be Cmd 
Msg (capital M message, which is an actual type in the example file), but I 
don't see how one of those is returned from Websocket.send.  Websocket.send 
doesn't know about the types in the websocket example, how could it return 
one of them?

This is an issue for me because I want to pass a partial application of 
WebSocket.send to a subcomponent, which will save the ftn into a state 
structure.  So passing (Websocket.send "someaddress"), into an init 
function, which would put it into a struct like so:

type alias Model =
  { sendf : (String -> Cmd msg)
  , otherstuff: String
  }

Then in my update function in the subcomponent the plan would be to call 
"sendf".  Problem is the compiler wants me to specify the type of "msg", 
and I have no idea what that might be.  


-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[elm-discuss] Task ports: A proposal to make it easier to integrate JS with Elm.

2016-08-13 Thread James Wilson
The problem

ports as they stand are fundamentally incompatible with Tasks. Being backed 
by Cmd's, they are harder to compose. A frustration of mine is that often 
we are directed to "just use ports" when a proper interface to some native 
API is not yet available, but this leads to our Msg types growing and more 
significant changes being required when eventually the proper interface is 
made available.

Also, many JS interop things I find myself wanting to do are fundamentally 
one-shot functions which I expect a result back into Elm from immediately, 
or otherwise just want to compose with other Task based things. Some 
examples that come to mind of one-shot tasks you may want to compose rather 
than use the streaming interface that ports provide:

   - Getting items from local/sessionStorage
   - .. really, most things involving working with the Web API that arent 
   yet implemented in Elm.
   - Embedding JS widgets into Elm elements
   - Using a JS library for doing things like hashing passwords or 
   obtaining some data back from some custom service
   - Interacting with things like Electron for creating apps that can run 
   in the desktop and interact with the filesystem etc.
   

The solution

Task ports. The idea is that these are defined the same way that Ports in 
elm currently are, but they return a Task type rather than a Cmd or Sub 
type. On the JS Side, we attach a function to the Elm app that returns a 
Promise, and on the Elm side we wait for the Promise returned to reject or 
resolve, and marhsall the error or result from the promise into the error 
or result type required by the Task type of the port.

Let's see how this might work:


*Ports.elm:*

port apiSession: Task String SessionId



*Main.elm:*

import Ports
import Json.Decode as Decode
import Task exposing (andThen)


-- get an API session from JS land and make an http request using it
-- given some path and a decoder to decipher the result:
apiRequest : String -> Decoder a -> Task ApiError a
apiRequest path decoder =
  let
headers sessId =
[ ("Content-Type", "application/json")
, ("MyApp-SessionId", sessId)
]


req sessId = Http.send Http.defaultSettings
{ verb = "POST"
, headers = headers sessId
, url = path
}


decodeResponse res = Decode.decodeString decoder -- ...handle error etc
  in
Ports.apiSession `andThen` req `andThen` decodeResponse


*App.js:*

Elm.Main.ports.apiSession = function(){
return new Promise(function(resolve,reject){


var sess = localStorage.getItem("sessionId");
if(!sess) reject("NO_SESSION");
else resolve(sess);


});
}

var app = Elm.Main.fullscreen();




Here, we use a tiny bit of JS to access localStorage and pull out a session 
ID. This function is used whenever the apiRequest Task is performed in Elm, 
and composes nicely into our apiRequest without the need for a complicated 
effect manager or threading a sessionId through everywhere just because we 
need to get it from a Cmd based port.

One of the nice things about this is that there is minimal refactoring to 
do for those things that do eventually receive coverage in the Elm Web API 
- you're just swapping out Tasks for other Tasks. As the Web API will 
always be changing, I think that having a nice way to make JS polyfills 
like this will always have some value, let alone for interacting with 
libraries written in JS that haven't or won't ever be ported to Elm.

Elm would continue to make the same guarantees as with other ports; if the 
task port can't marshall the response back into Elm an error would be 
thrown along the same lines as is currently done via ports.

Summary

- regular ports only let you send data off or receive data back, not both.
- Cmd's and Sub's are not composable
- Task based ports allow you to create a new Task that is backed by JS
- Task based ports allow for better composition and less friction when the 
backing JS is eventually implemented in Elm.

I'd love to hear what people think about this. Perhaps I'm missing some big 
issues with the idea for instance, or maybe it's an awesome idea :) What do 
you all think?

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [elm-discuss] Re: share-elm.com seems to be down?

2016-08-13 Thread Duane Johnson
Can confirm (it's down for me as well).

On Fri, Aug 12, 2016 at 10:00 PM, Carlos De la Guardia 
wrote:

> Seems to be down again?
>
> On Wednesday, March 4, 2015 at 10:52:25 PM UTC-8, Janis Voigtländer wrote:
>>
>> Or something like that. I get a "502 Bad Gateway" error.
>>
>> --
> You received this message because you are subscribed to the Google Groups
> "Elm Discuss" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to elm-discuss+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[elm-discuss] Re: How do I write an elm-check producer for a recursive data structure?

2016-08-13 Thread John Watson
Max, I'm getting frustrated in trying to use the npm-installed elm-test 
TestRunner.  Whereas with version 1.1.0 of elm-test and elm-check, to run 
my tests  I could just use:

main =
  ElmTest.runSuite (Check.Test.evidenceToTest evidence)

it's not at all clear to me what I need to do now.  I've attempted to 
follow the instructions on the main documentation page of elm-test 2.0.0 to 
(re)-install the runner.  When I try to use elm-test init it prompts me to 
add dependencies on deadfoxygrandpa.elm-test and 
also laszlopandy/elm-console which is surely wrong.  Is it trying to 
install an old version?  I'm getting very confused.


On Saturday, 13 August 2016 10:29:14 UTC+1, John Watson wrote:
>
> Many thanks for the replies, Max and Janis.
>
> Yes - exactly - I wanted some sort of size combinator, couldn't find one 
> and just experimented to see what would happen.  It would be lovely to have 
> this built in to Fuzz.
>
> Max - many thanks for pointing out Fuzz - I wasn't aware of it. I see that 
> elm-check is now deprecated - I guess it must have happened quite recently. 
>  I'd be very happy to make the recursion depth explicit as in your second 
> example.  I'll play with it for a bit and report back what I find.  I very 
> much like the fact that you can indicate frequencies for the different ADT 
> constructors and also that (I presume) you no longer have to write your own 
> shrinkers.  I was a initially a bit concerned about *frequencyOrCrash *but 
> it seems that if you're sensible with your frequencies, then actual crashes 
> won't happen.
>
> On Friday, 12 August 2016 15:14:05 UTC+1, John Watson wrote:
>>
>> I have simplified my data type to:
>>
>> type Music =
>>   Note Int
>>   | Rest Int
>>   | Seq Music Music
>>   | Par Music Music
>>
>> I have attempted to write a Producer (see this gist 
>> ) 
>> where the runtime crashes with:
>>
>> TypeError: _user$project$Producers$parseq is not a function
>>
>> If I replace the recursive generation step in the parseq 
>> 
>>  
>> Producer, then I get no crash, the check works (but of course on limited 
>> data).  Judging by the lack of any log output, I don't think I'm recursing 
>> forever - I wonder if perhaps it could be another manifestation of this 
>>  problem?
>>
>> Any help gratefully accepted.
>>
>

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [elm-discuss] Re: Design of Large Elm apps

2016-08-13 Thread Rex van der Spuy
Thanks so much Richard, that's absolutely fascinating!

The way that I've been building my current generation of Elm apps has been 
modelled on the Counter/Pair example.
So it's not uncommon for me to have apps with nested M/V/U models 3 levels 
deep (For example, a "page" containing a "panel" which contains a "button" 
- that kind of structure.)
And, yup, it's a kind of a pain to manage the chain of updates through 
those nested structure and bubble up their effects.
So just having one structure to deal with sounds kind of. easy and nice 
:)

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[elm-discuss] Re: How do I write an elm-check producer for a recursive data structure?

2016-08-13 Thread John Watson
Many thanks for the replies, Max and Janis.

Yes - exactly - I wanted some sort of size combinator, couldn't find one 
and just experimented to see what would happen.  It would be lovely to have 
this built in to Fuzz.

Max - many thanks for pointing out Fuzz - I wasn't aware of it. I see that 
elm-check is now deprecated - I guess it must have happened quite recently. 
 I'd be very happy to make the recursion depth explicit as in your second 
example.  I'll play with it for a bit and report back what I find.  I very 
much like the fact that you can indicate frequencies for the different ADT 
constructors and also that (I presume) you no longer have to write your own 
shrinkers.  I was a initially a bit concerned about *frequencyOrCrash *but 
it seems that if you're sensible with your frequencies, then actual crashes 
won't happen.

On Friday, 12 August 2016 15:14:05 UTC+1, John Watson wrote:
>
> I have simplified my data type to:
>
> type Music =
>   Note Int
>   | Rest Int
>   | Seq Music Music
>   | Par Music Music
>
> I have attempted to write a Producer (see this gist 
> ) 
> where the runtime crashes with:
>
> TypeError: _user$project$Producers$parseq is not a function
>
> If I replace the recursive generation step in the parseq 
> 
>  
> Producer, then I get no crash, the check works (but of course on limited 
> data).  Judging by the lack of any log output, I don't think I'm recursing 
> forever - I wonder if perhaps it could be another manifestation of this 
>  problem?
>
> Any help gratefully accepted.
>

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [elm-discuss] Re: Design of Large Elm apps

2016-08-13 Thread Richard Feldman

>
> Are you suggesting that each self-contained Elm "app" ("page", "game" 
> etc.) should only have one Model/View/Update and avoid using nested modules 
> for sub-components?

 
Yeah - 

do you mean that something like the nested counter example from the Elm 
> Archtecture guide is a bad idea?


It's not *necessarily* a bad idea, just not the first thing you should 
reach for. Or the second thing you should reach for. Or the third thing you 
should reach for.

The first three things you should reach for are, in no particular order:

   1. Splitting view into smaller functions (without reorganizing Model or 
   update)
   2. Splitting Model into smaller values (without reorganizing view or 
   update)
   3. Splitting update into smaller functions (without reorganizing Model 
   or view)
   
Do one of these 3 things, one at a time, over and over, until either you're 
thinking "I need to split out some of this to reuse it elsewhere" (in which 
case you enter the realm of API design, and there is no one-size-fits-all 
answer to what you should do next), or you find yourself thinking "even 
after these small refactors, there is a big chunk of code that still feels 
unwieldy, and it's self-contained enough that I could separate it out into 
essentially its own little application, and have it communicate with the 
rest of the application, and that communication overhead sounds like it 
would be worth it."

As the guide says:

what happens when our code starts getting big? It would be crazy to just 
> grow your Model and update functions endlessly. This is where Elm's 
> module system comes in.


The nested counter is a demonstration of how to do this technique *once 
your code base grows crazy enough to make it seem worthwhile*, but it's 
super common to build something straightforward enough that it never needs 
this kind of nesting at all!

I get where you are coming from in saying that the update function becomes 
> essentially fifty smaller functions. Some of the questions on modularity 
> then stem from whether you ever expect someone to read through and consider 
> an entire Elm module or whether you expect that people will make changes to 
> pieces of code within a module and simply ignore the rest of it. The latter 
> is probably common no matter what. To me, it's a question of whether the 
> former should be viable or whether it's basically considered irrelevant as 
> a practice.
>

In my experience the latter hasn't been a problem, so it doesn't seem like 
looking for a solution would be a good use of anyone's time. ;) 

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[elm-discuss] Re: Design question: using Dict, List with index, or Array (or something I'm not aware of)

2016-08-13 Thread Ian Mackenzie
My initial reaction is also #3. I think it's totally sensible to do a bit 
of transformation when serializing/deserializing, and more important to 
optimize your model for its use in view and update.

On Friday, 12 August 2016 23:03:34 UTC+10, Robert Walter wrote:
>
> Hello,
>
> following scenario: In my Model, I want to keep track of a collection of 
> items as well as the currently active item. Sounds simple enough, but there 
> are some constraints. I want to serialize my Model (use programWithFlags), 
> so I cannot use a Dict directly to the best of my knowledge. I need to be 
> able to sort the collection and be able to append items at the beginning as 
> well at the end.
> I've come up with the following options and it would be appreciated if I 
> could get some feedback on what the community thinks is best and why.
>
> Option 1: List and explicit Item
> type alias Model = 
>   { collection : List Item
>   , itemActive : Item 
>   }
>
>
> type alias Item =
>   { name : String 
>   }
>
> Downside: I have to manually update the list if the item changes (it's 
> what I have in place currently and it is somewhat obvious to me that this 
> is not best).
>
> Option 2: List with index
> type alias Model = 
>   { collection : List Item
>   , itemActive : Int 
>   }
>
>
> type alias Item =
>   { name : String 
>   }
>
> Downside: accessing a random item in a list is expensive (although in 
> practice my collection is never going to be very long, it could get 
> arbitrarily long).
>
> Option 3: Dict with index
> type alias Model = 
>   { collection : Dict Int Item
>   , itemActive : Int 
>   }
>
>
> type alias Item =
>   { name : String 
>   }
>
> Downside: Dict is not supported by programWithFlags, so I'd have to 
> transform it to a different representation for serialization
>
> Option 4: array with index
> type alias Model = 
>   { collection : Array Item
>   , itemActive : Item 
>   }
>
>
> type alias Item =
>   { name : String 
>   }
>
> Downside: I need to perform some operations that don't seem to be first 
> class array operations, namely sort the array by Item.name and insert items 
> at the front
>
> I think I know how to implement each of these approaches, but maybe I'm 
> missing an even better fit for my use case. Currently I prefer Option 3. 
> Even though it might need a bit more work on the serialization / 
> de-serialization side, I feel like a Dict would be the best fit for my use 
> case.
>
> Thanks in advance,
> Robert
>

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.