[elm-discuss] Re: Multiple "Middleware" pattern instead of single *.program

2017-11-02 Thread Martin Janiczek


On Thursday, November 2, 2017 at 12:56:52 PM UTC+1, Martin Janiczek wrote:
 

> I have added a Navigation middleware example, see the updated demo: 
> https://janiczek.github.io/middleware/index.html
> (Because *elm-lang/navigation* doesn't expose the *Location -> msg -> Sub 
> msg*, I've had to copy it to the user-space code to be able to connect 
> the subscription to the middleware.)
>

(Of course I meant *(Location -> msg) -> Sub msg*.)

It seems to me that the Navigation example doesn't gain much from being 
written in middleware pattern. It's *better than the *.program approach* in 
that it can compose, but it's *worse than Sub approach* in that user 
doesn't see where the Location msg came from. (In my opinion, it's better 
to be explicit.)
The time-travel middleware does, I think, still have its value in being in 
the middleware pattern: it's more "invasive" change, *view* and all, and 
wouldn't be suited by simple Cmd/Sub.

I assume the reason Navigation has opted for the *.program approach, is the 
custom *init* function. This (init) is one thing I haven't yet thought 
about much for the middleware, and is probably subject to change. There 
probably exists some nice middleware example that would make the API more 
clear. Food for thought :)

-- 
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: Multiple "Middleware" pattern instead of single *.program

2017-11-02 Thread Martin Janiczek


On Thursday, November 2, 2017 at 10:30:10 AM UTC+1, Rupert Smith wrote: 
>
> One problem I had was with TimeTravel.program which I was wrapping a 
> RouteUrl.navigationApp with. All the messages were then nested at the 
> time-travel level, and its UI did not support nested filtering, so I could 
> not easily filter out animation messages. It occurs to me that if each 
> middleware knows about the next layer, and has wrap/unwrap functions for 
> it, that it would be possible to have set up the time-travel layer to 
> unwrap the nested messages, if I had such a system as yours.
>

Right now that seems problematic: the composing functions can't inspect the 
types in runtime (to decide how much to unwrap), and the amount of wrapping 
the time-travel middleware will see depends on where you'll put it in the 
chain. It would make sense to put it right next to the user program - no 
middle layers to unwrap then.
 

> Would love to see what a navigation example looks like.
>

I have added a Navigation middleware example, see the updated demo: 
https://janiczek.github.io/middleware/index.html
(Because *elm-lang/navigation* doesn't expose the *Location -> msg -> Sub 
msg*, I've had to copy it to the user-space code to be able to connect the 
subscription to the middleware.)

This brought a minor change to the API: middleware's *subscriptions* now 
take the *programMsgs* record and return *(Sub msg, Sub programMsg)*.

-- 
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] Multiple "Middleware" pattern instead of single *.program

2017-11-01 Thread Martin Janiczek
Hello elm-discuss!

I've been thinking about the **.program* pattern. Currently one has to 
choose one of the many different *.program functions 
 and implement the rest 
of the functionality themselves, ie. they can't mix and match, say, 
*Navigation.program* and *TimeTravel.Html.program*.

A way to solve that would be to specify a list of "middlewares" that each 
do a specific task, and have a "clean" program they all augment:

main =
combineMiddleware
Navigation.middleware
TimeTravel.middleware
DropboxAuth.middleware
App.program

I have tried to implement such a pattern and want to share it and ask for 
opinions. *This could, after all, be a very bad idea!*



Some links:

   - GitHub  (I didn't want to 
   publish that as a package just yet, but if it helps somebody, tell me and I 
   can do that)
   - Tour of the code:
  - The *main* function 
  
  - The *program* (business logic) 
  
 
  (a counter)
  - A *middleware* "talking" to the program 
  

 (returns 
  it from update)
  - A *middleware* logging "all the Msgs under it" 
  
 
(this 
  + the Reset middleware could, with a bit of effort, become a Debugger 
  middleware)
  - A *middleware* using its own Subs 
  

 (the 
  middlewares can use Subs, Cmds, have their own model)
   


This allows people to combine multiple behaviours instead of being limited 
to just one.

*Questions I'm pondering are:*


   1. Is this a good idea at all?
   2. Comparison to the "fractal TEA" that we generally shun now. (Hiding 
   of behaviour; in fractal TEA one sees the extra functionality in the model, 
   here it's almost invisible; does one need to see it? This approach avoids 
   some boilerplate -- the only thing end user needs to supply is a Msg 
   constructor, similar to *.program)
   3. Does this encourage some bad practices, code smell, OOP in a FP 
   language, componentization? Good/bad? (If bad, is the *.program pattern we 
   currently somehow embrace OK then? I'd say it does things /hides behaviour/ 
   basically the same way.)



And, for the interested, some implementation details:

   - Each middleware knows about the next model in the chain (they're 
   nested), but can't inspect it. (If it used concrete type instead of a type 
   variable, it would limit what other middlewares/programs can be next to it.)
   - The Msgs are also nested: each middleware has to have one Msg for 
   wrapping the Msgs of the next middleware/program in the chain.
   - All middlewares can send messages *to the program* (but not to each 
   other):
  - the program exposes a record with Msg constructors it offers 
  alongside update, init, etc.
  - each middleware declares what Msg constructors it needs (through an 
  extensible record) -- very similar to how Navigation.program needs a 
  Msg constructor for the location changes 
  

  .
  - the compiler makes sure all middleware Msg needs are satisfied
  - middleware's update gets the record with the constructors as an 
  argument, and returns a Maybe Program.Msg
  - the Msg gets threaded through the Elm Runtime as any other, and the 
  user gets a nice clean Msg in their update.
   
And some API:

middleware : 
{ init : (innerModel, Cmd innerMsg) -> (ownModel, Cmd ownMsg)
, update : ownMsg -> ownModel -> programMsgs -> (ownModel, Cmd ownMsg, 
Maybe programMsg)
, subscriptions : ownModel -> Sub ownMsg
, view : ownModel -> innerHtml as Html ownMsg -> Html ownMsg
, wrapMsg : innerMsg -> ownMsg
, unwrapMsg : ownMsg -> Maybe innerMsg
}

where

ownModel = { ownFields | innerModel : innerModel }

program :
{ init : (model, Cmd msg)
, update : msg -> model -> (model, Cmd msg)
, subscriptions : model -> Sub msg
, view : model -> Html msg
, programMsgs : programMsgs
}

where

programMsgs = (eg.) { locationChanged : Location -> Msg }



-- 
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: Proposal: move Random.Extra.constant to Random

2017-10-26 Thread Martin Janiczek
IIRC from conversations with Francesco, this thread started as a reaction to 
seeing that core's (to be 0.19) Random incorporated your Random.PCG's code but 
omitted `constant`.

Can we know the reasoning behind the "it shouldn't be there" opinion?

-- 
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: Source Maps? /was Elm Dev Tools

2017-04-19 Thread Martin Janiczek
I'm working on code coverage tool, although not in the "source maps + 
Istanbul" way:
https://groups.google.com/forum/#!topic/elm-dev/1tHjTG1z6EM

It currently lives on Github in Janiczek/elm-compiler 
.

https://github.com/Janiczek/elm-make/commit/1497add08e790bc10e004a7cbefb3f5e02527e92
https://github.com/Janiczek/elm-compiler/commit/303068059656e3e983d5d3f490739e220c2bef9e

-- 
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] Elm "missing library / I was blocked by ..." scoreboard?

2017-04-12 Thread Martin Janiczek
Would it be a good idea to create Elm "scoreboard" at canny.io or something 
similar? (See https://react-native.canny.io/feature-requests for example)

Seeing Twitter @elmlang mentions like: "It's sad that we lack touch 
subscription support on @elmlang", it seems to me that we could aggregate 
these on the canny.io page and in some time see what are the biggest pains 
(ie. touch events / web audio / window scroll subscriptions / ...)

On Slack it has been noted that GitHub issues could serve the same purpose, 
although it lacks the UI (sort by most wanted feature) and from the top of 
my head I don't know which repo would be good for that. 
elm-community/something?

-- 
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: No Runtime Exceptions - Still not computing

2016-10-08 Thread Martin Janiczek
Dave, how do you think about JavaScript Promises? Where you code for the 
happy path (the chain of Promise.resolve().then().then().then()), any of 
which can throw, and have a .catch() handler that catches whatever the 
thrown value was and does something about it.
The Elm Result type is very similar to this.

Promise.resolve(myValue) ~= Ok myValue
Promise.reject(myErrorData) ~= Err myErrorData
promise.then(fn) ~= myResult.andThen(fn) or myResult.map(fn)
promise.catch(fn) ~= case myResult of Err x -> fn x


Again, a specific example would help. Elm programs are not written the way 
C, C#, Java programs are written. Clojure is closer but because of Java 
interop reasons hasn't adopted much of the Maybe / Result / ... goodness 
and instead has nils like Java has. In Elm the erorrs are explicit (like 
you say, part of the return type). 
Read: http://blog.jenkster.com/2016/06/how-elm-slays-a-ui-antipattern.html 
for how Elm solves the Server Down error you mentioned.

Malformed JSON is also reported not with exceptions but with Result. Either 
you get your value in Ok, or helpful error message in Err. You have to 
handle both cases, it doesn't propagate up, it doesn't throw a runtime 
exception, the user sees what you decided to show him in that scenario. 
Essentially the Elm compiler tells you "This could blow up - you told me 
what to do if the JSON is OK, but what if it is not?"

On Friday, October 7, 2016 at 10:05:50 PM UTC+2, Dave Ford wrote:
>
>
>
> On Fri, Oct 7, 2016 at 11:33 AM, Kasey Speakman  > wrote: 
>>
>> Then at the edge of the application, I can deal with the errors
>>
> Yes. This is what I am trying to figure out. How to deal with that class 
> of errors at the "edge". 
>  
> Thanks.
>
>

-- 
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: Possible compiler bug?

2016-08-22 Thread Martin Janiczek
Sure, I just copied the function definition to my module that uses 
Random.Pcg instead of Random.
There was no need to change the implementation, it just uses 
Random.Pcg.constant instead of Random.Extra.constant, I believe.

import Random.Pcg as Random exposing (Generator)

{-| Turn a list of generators into a generator of lists.

This is a version working with Random.Pcg.
-}
together : List (Generator a) -> Generator (List a)
together generators =
case generators of
[] ->
Random.constant []

g :: gs ->
Random.map2 (::) g (together gs)



On Friday, August 19, 2016 at 4:24:07 PM UTC+2, Max Goldstein wrote:
>
> > I have created my own Random.Pcg `together` and it compiles.
>
> Would you mind clarifying what you mean by this?
>

-- 
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: Possible compiler bug?

2016-08-19 Thread Martin Janiczek
The namespaces get 'merged' - ie. if you do:

module A exposing (a, b, c)
---
module B exposing (d, e, f)
---
module C exposing (..)

import A
import B as A

then nothing's wrong - you can do A.a through to A.f without a problem.

Problems happen when collision happens, ie.

module B exposing (c)

The compiler will then tell you that the imports are ambiguous.

On Friday, August 19, 2016 at 11:29:00 AM UTC+2, John Bugner wrote:
>
> Why are duplicate imports allowed in the first place?
>
> On Friday, August 19, 2016 at 2:20:50 AM UTC-5, Martin Janiczek wrote:
>>
>> Hello,
>>
>> I've been stumped by a compiler error which I can't figure out. I think 
>> it's a compiler bug. (I'd like to maybe help fix that and contribute a PR - 
>> even though it might get incorporated into elm-compiler wy later or not 
>> at all, I could have my own elm-compiler and continue on the project :) )
>>
>> import Fuzz exposing (Fuzzer)
>> import Random.Pcg as Random
>> import Random.Extra as Random
>> import Shrink
>>
>>
>> type alias Op op =
>> { generator : Random.Generator op }
>>
>>
>> opsFuzzer : List (Op op) -> Fuzzer (List op)
>> opsFuzzer ops =
>> Fuzz.custom
>> (Random.together (List.map .generator ops))
>> (Shrink.list Shrink.noShrink)
>>
>>
>> -- TYPE MISMATCH - 
>> src/A.elm
>>
>> The type annotation for `opsFuzzer` does not match its definition.
>>
>> 21| opsFuzzer : List (Op op) -> Fuzzer (List op)
>> 
>> The type annotation is saying:
>>
>> List { generator : Random.Generator b } -> Fuzzer (List b)
>>
>> But I am inferring that the definition has this type:
>>
>> List { generator : Random.Generator a } -> Fuzzer (List b)
>>
>> -- TYPE MISMATCH - 
>> src/A.elm
>>
>> The 1st argument to function `custom` is causing a mismatch.
>>
>> 23| Fuzz.custom
>> 24|>(Random.together (List.map .generator ops))
>> 25| (Shrink.list Shrink.noShrink)
>>
>> Function `custom` is expecting the 1st argument to be:
>>
>> Random.Generator a
>>
>> But it is:
>>
>> Random.Generator (List a)
>>
>> Detected errors in 1 module.
>>
>> (The larger codebase is here: 
>> https://github.com/Janiczek/elm-test/commit/9b8323d4721cea0f0420c1440d31b79989b7528a
>> )
>>
>> The compiler is telling me my types don't match but I think they do (even 
>> by substituting the types by hand).
>> Does anybody have any idea on what to do with this?
>>
>

-- 
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] Possible compiler bug?

2016-08-19 Thread Martin Janiczek
Shoot, you're right!
(And I thought I checked for that.)

I have created my own Random.Pcg `together` and it compiles.
I will at least post this to *error-message-catalog* :)

Thank you!

On Friday, August 19, 2016 at 10:14:28 AM UTC+2, Nick H wrote:
>
> I think this error might have to do with these two lines:
>
> import Random.Pcg as Random
> import Random.Extra as Random
>
> These two libraries are not designed to work together. Random.Extra works 
> with the Generator type that is defined in the core library. Random.Pcg 
> defines its own type called Generator
>
> So when you call Random.together, you are passing it a 
> Random.Pcg.Generator, but it is expecting a core Generator.
>
>
> On Fri, Aug 19, 2016 at 12:20 AM, Martin Janiczek <mar...@janiczek.cz 
> > wrote:
>
>> Hello,
>>
>> I've been stumped by a compiler error which I can't figure out. I think 
>> it's a compiler bug. (I'd like to maybe help fix that and contribute a PR - 
>> even though it might get incorporated into elm-compiler wy later or not 
>> at all, I could have my own elm-compiler and continue on the project :) )
>>
>> import Fuzz exposing (Fuzzer)
>> import Random.Pcg as Random
>> import Random.Extra as Random
>> import Shrink
>>
>>
>> type alias Op op =
>> { generator : Random.Generator op }
>>
>>
>> opsFuzzer : List (Op op) -> Fuzzer (List op)
>> opsFuzzer ops =
>> Fuzz.custom
>> (Random.together (List.map .generator ops))
>> (Shrink.list Shrink.noShrink)
>>
>>
>> -- TYPE MISMATCH - 
>> src/A.elm
>>
>> The type annotation for `opsFuzzer` does not match its definition.
>>
>> 21| opsFuzzer : List (Op op) -> Fuzzer (List op)
>> 
>> The type annotation is saying:
>>
>> List { generator : Random.Generator b } -> Fuzzer (List b)
>>
>> But I am inferring that the definition has this type:
>>
>> List { generator : Random.Generator a } -> Fuzzer (List b)
>>
>> -- TYPE MISMATCH - 
>> src/A.elm
>>
>> The 1st argument to function `custom` is causing a mismatch.
>>
>> 23| Fuzz.custom
>> 24|>(Random.together (List.map .generator ops))
>> 25| (Shrink.list Shrink.noShrink)
>>
>> Function `custom` is expecting the 1st argument to be:
>>
>> Random.Generator a
>>
>> But it is:
>>
>> Random.Generator (List a)
>>
>> Detected errors in 1 module.
>>
>> (The larger codebase is here: 
>> https://github.com/Janiczek/elm-test/commit/9b8323d4721cea0f0420c1440d31b79989b7528a
>> )
>>
>> The compiler is telling me my types don't match but I think they do (even 
>> by substituting the types by hand).
>> Does anybody have any idea on what to do with this?
>>
>> -- 
>> 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...@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] Possible compiler bug?

2016-08-19 Thread Martin Janiczek
Hello,

I've been stumped by a compiler error which I can't figure out. I think 
it's a compiler bug. (I'd like to maybe help fix that and contribute a PR - 
even though it might get incorporated into elm-compiler wy later or not 
at all, I could have my own elm-compiler and continue on the project :) )

import Fuzz exposing (Fuzzer)
import Random.Pcg as Random
import Random.Extra as Random
import Shrink


type alias Op op =
{ generator : Random.Generator op }


opsFuzzer : List (Op op) -> Fuzzer (List op)
opsFuzzer ops =
Fuzz.custom
(Random.together (List.map .generator ops))
(Shrink.list Shrink.noShrink)


-- TYPE MISMATCH - src/A
.elm

The type annotation for `opsFuzzer` does not match its definition.

21| opsFuzzer : List (Op op) -> Fuzzer (List op)

The type annotation is saying:

List { generator : Random.Generator b } -> Fuzzer (List b)

But I am inferring that the definition has this type:

List { generator : Random.Generator a } -> Fuzzer (List b)

-- TYPE MISMATCH - src/A
.elm

The 1st argument to function `custom` is causing a mismatch.

23| Fuzz.custom
24|>(Random.together (List.map .generator ops))
25| (Shrink.list Shrink.noShrink)

Function `custom` is expecting the 1st argument to be:

Random.Generator a

But it is:

Random.Generator (List a)

Detected errors in 1 module.

(The larger codebase is 
here: 
https://github.com/Janiczek/elm-test/commit/9b8323d4721cea0f0420c1440d31b79989b7528a)

The compiler is telling me my types don't match but I think they do (even 
by substituting the types by hand).
Does anybody have any idea on what to do with this?

-- 
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.