Re: [elm-discuss] elm-css with type classes (a response to the Elm Town podcast)

2017-04-27 Thread OvermindDL1
Yep, that is all trivial with Polymorphic Variants if you want them shared.

In essence, you know how a normal variant is, like this (in OCaml syntax 
since that is what I'm more comfortable with, but it's close enough to Elm, 
'almost' identical)
```ocaml
type Vwoop =
| Infinite
| Int of integer

type Broop =
| Infinite
| Float of float
```
And say you have some functions like (again in OCaml syntax):
```ocaml
let vloo = function
| Infinite -> "infinite"
| Int i -> string_of_integer i

let bloo = function
| Infinite -> "all"
| Float f -> string_of_float f
```
Now this will not compile, there are two Infinite's in scope and so it does 
not know which you want or mean without qualifying them by name.  If 
however we did not have the variant types above and just used polymorphic 
variants:
```ocaml
let vloo = function
| `Infinite -> "infinite"
| `Int i -> string_of_int i

let bloo = function
| `Infinite -> "all"
| `Float f -> string_of_float f
```
And this all works fine, you could use it like this no problem:
```ocaml
let whatever = String.concat [vloo `Infinite; bloo `Infinite]
```
And `whatever` will become the string "infiniteall" as expected.

A Polymorphic Variant is just a 'globally scoped' variant, and it is not 
based on the name but the entire type, so ``` `Int ``` is different from 
``` `Int 42 ```, so this will *not* compile:
```ocaml
let this_does_not_compile = vloo (`Int 42.7)
```
This will give you the error (I just ran this to test):
```
Line 9, 33: Error: This expression has type [> `Int of float ]
   but an expression was expected of type [< `Infinite | `Int of int ]
   Types for tag `Int are incompatible
```
So it is trying to pass in the specific type of `Int of float, yet the 
function only accepts the closed set of polymorphic varianst of `Infinite 
or `Int of int.  It then goes on to clarify that the `Int is fine but the 
type inside the `Int is wrong/incompatible.  For further example if I try 
to past in `Blah it returns:
```
Line 9, 33: Error: This expression has type [> `Blah ]
   but an expression was expected of type [< `Infinite | `Int of int ]
   The second variant type does not allow tag(s) `Blah
```
It is type safe the whole way through.  And of course you can add types to 
it as well if you want, they are exactly as they appear in the error 
messages.


For note, `function` is a keyword in OCaml that is short for a combination 
fn and match, so these are the same:
```ocaml
let tester = function
| `Test1 -> "test1"
| `Test2 -> "test2"

let tester t = match t with
| `Test1 -> "test1"
| `Test2 -> "test2"
```

For note, polymorphic variants are just like normal variants, in the 
generated javascript they get tagged like any normal variant, just with a 
larger number due to their scope.  The above tester/bloo/vloo functions 
compile to this javascript:
```javascript
var Pervasives = require("stdlib/pervasives");

function vloo(param) {
  if (typeof param === "number") {
return "infinite";
  }
  else {
return Pervasives.string_of_int(param[1]);
  }
}

function bloo(param) {
  if (typeof param === "number") {
return "all";
  }
  else {
return Pervasives.string_of_float(param[1]);
  }
}

function tester(t) {
  if (t >= 549646208) {
return "test2";
  }
  else {
return "test1";
  }
}
```

But yes, as you can see polymorphic variants types can be open (accepting 
any) or closed (accepting a limited subset), fully typed and safe the whole 
way down.

A lot of people consider polymorphic variants existence a bit of a wart, 
but I do not see it, they are highly highly useful in specific cases (like 
DSEL's here), but I do agree they can be abused when normal variants are 
better...


On Thursday, April 27, 2017 at 2:26:10 PM UTC-6, Mark Hamburg wrote:
>
> Maybe this is covered in OCaml's polymorpic variants — I couldn't tell 
> from a quick skim — but another feature that would cover this without 
> introducing type classes is support for more arbitrary union/sum types. 
> That way, one could write something like:
>
> type Auto = Auto
>
>
> type alias LengthOrAuto = Int + Auto -- is this a type or a type alias, 
> I'm not sure
>
> margin : LengthOrAuto -> Style
>
> Handwaving type checking rules would require that a type passed to 
> something that was expecting a union type needs to cover a subset of that 
> union type. Case statements would be used to do the discrimination.
>
> The potentially interesting things that come out of something like this 
> are that one could imagine a union of Maybe and Result which would allow 
> for a value or an error or nothing. This has got to have been explored 
> somewhere before. I have no idea what sort of problems it might create for 
> the type system.
>
> Mark
>
> On Thu, Apr 27, 2017 at 10:53 AM, OvermindDL1  > wrote:
>
>> Actually this sounds to exactly like the use-case for OCaml's Polymorphic 
>> Variants.  In OCaml you could easily use just `Hidden for both of your 
>> examples, 

Re: [elm-discuss] elm-css with type classes (a response to the Elm Town podcast)

2017-04-27 Thread Mark Hamburg
Maybe this is covered in OCaml's polymorpic variants — I couldn't tell from
a quick skim — but another feature that would cover this without
introducing type classes is support for more arbitrary union/sum types.
That way, one could write something like:

type Auto = Auto


type alias LengthOrAuto = Int + Auto -- is this a type or a type alias, I'm
not sure

margin : LengthOrAuto -> Style

Handwaving type checking rules would require that a type passed to
something that was expecting a union type needs to cover a subset of that
union type. Case statements would be used to do the discrimination.

The potentially interesting things that come out of something like this are
that one could imagine a union of Maybe and Result which would allow for a
value or an error or nothing. This has got to have been explored somewhere
before. I have no idea what sort of problems it might create for the type
system.

Mark

On Thu, Apr 27, 2017 at 10:53 AM, OvermindDL1  wrote:

> Actually this sounds to exactly like the use-case for OCaml's Polymorphic
> Variants.  In OCaml you could easily use just `Hidden for both of your
> examples, fully type checked, type safe, etc... etc...  Polymorphic
> Variants are just global Variants that are unnamed.  A function can take a
> bounded or unbounded set of them and are perfectly suited for an abstract
> CSS DSL while being readable in both usage and implementation.
>
> And yes, I agree about type classes, they are extremely over-used in
> Haskell where something like OCaml's Implicit Modules would be such a
> significantly better fit for...
>
>
> On Thursday, April 27, 2017 at 6:21:22 AM UTC-6, Mitchell Rosen wrote:
>>
>> Hi Joey,
>>
>> Indeed, basic ADTs are one way to model the DSL. The problem then arises
>> when you want to reuse the name "auto" for another key.
>>
>> I may not have been clear, so I'll try to summarize my post here. How
>> might elm-css look if there were different features in Elm? As it stands,
>> the library seems to be fighting hard against the language, and the result
>> far from beginner-friendly.
>>
>> Type classes are one such extension, and I sketched out how one might
>> implement this library using them. As you mentioned, ADTs are another.
>>
>> In this particular case, type classes, as flawed as they are, seem vastly
>> superior to the row-types approach. But, I'm definitely open to having my
>> mind changed! I'm just not comfortable enough with row types as a language
>> feature to really have an intuitive understanding of when to use them, and
>> when to not.
>>
>> But, anyways, I totally agree that keeping it simple with ADTs is what
>> you should do most of the time. It's only when you're writing library code
>> to be used by the community that you should start obsessing over the
>> ergonomics.
>>
>> --
> 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.


Re: [elm-discuss] elm-css with type classes (a response to the Elm Town podcast)

2017-04-27 Thread OvermindDL1
Actually this sounds to exactly like the use-case for OCaml's Polymorphic 
Variants.  In OCaml you could easily use just `Hidden for both of your 
examples, fully type checked, type safe, etc... etc...  Polymorphic 
Variants are just global Variants that are unnamed.  A function can take a 
bounded or unbounded set of them and are perfectly suited for an abstract 
CSS DSL while being readable in both usage and implementation.

And yes, I agree about type classes, they are extremely over-used in 
Haskell where something like OCaml's Implicit Modules would be such a 
significantly better fit for...


On Thursday, April 27, 2017 at 6:21:22 AM UTC-6, Mitchell Rosen wrote:
>
> Hi Joey,
>
> Indeed, basic ADTs are one way to model the DSL. The problem then arises 
> when you want to reuse the name "auto" for another key.
>
> I may not have been clear, so I'll try to summarize my post here. How 
> might elm-css look if there were different features in Elm? As it stands, 
> the library seems to be fighting hard against the language, and the result 
> far from beginner-friendly.
>
> Type classes are one such extension, and I sketched out how one might 
> implement this library using them. As you mentioned, ADTs are another.
>
> In this particular case, type classes, as flawed as they are, seem vastly 
> superior to the row-types approach. But, I'm definitely open to having my 
> mind changed! I'm just not comfortable enough with row types as a language 
> feature to really have an intuitive understanding of when to use them, and 
> when to not.
>
> But, anyways, I totally agree that keeping it simple with ADTs is what you 
> should do most of the time. It's only when you're writing library code to 
> be used by the community that you should start obsessing over the 
> ergonomics.
>
>

-- 
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] elm-css with type classes (a response to the Elm Town podcast)

2017-04-27 Thread Mitchell Rosen
Hi Joey,

Indeed, basic ADTs are one way to model the DSL. The problem then arises when 
you want to reuse the name "auto" for another key.

I may not have been clear, so I'll try to summarize my post here. How might 
elm-css look if there were different features in Elm? As it stands, the library 
seems to be fighting hard against the language, and the result far from 
beginner-friendly.

Type classes are one such extension, and I sketched out how one might implement 
this library using them. As you mentioned, ADTs are another.

In this particular case, type classes, as flawed as they are, seem vastly 
superior to the row-types approach. But, I'm definitely open to having my mind 
changed! I'm just not comfortable enough with row types as a language feature 
to really have an intuitive understanding of when to use them, and when to not.

But, anyways, I totally agree that keeping it simple with ADTs is what you 
should do most of the time. It's only when you're writing library code to be 
used by the community that you should start obsessing over the ergonomics.

-- 
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] elm-css with type classes (a response to the Elm Town podcast)

2017-04-27 Thread Joey Eremondi
I might be misunderstanding, but in your use case, you probably want a
tagged Union, what Haskell calls data, instead of type classes. Basically,
they're always preferable when you have a fixed number is variants you
want. Your margin function would then just pattern match.

type Margin = Auto | IntMargin Int

margin: Margin -> Style
margin m = case m of ...

Is there some visual overhead having to have a tag for Int? Yes. Is your
code clearer and simpler? Yes.

Haskell classes are made for abstractions with many instances defined
separately. Things like traversable, Monads, Monoid, etc. There are many
things fitting the pattern, and we want to give people the ability to
implement it for their own types. Most experienced Haskell coders would not
use a type class in your use case.

Classes also have problems if you want to make a list of margins for some
reason. Now you can't without existential types, which are a whole
different kettle of fish. Tagged unions don't have that problem.

On Apr 26, 2017 8:03 PM, "Mitchell Rosen"  wrote:

Hello all! I am a (very) beginner Elm programmer, but I know a fair bit of
Haskell. I listened to the most recent Elm Town podcast and was especially
intrigued by the discussion around a novel use of record types to solve a
real-world problem - embedding a nice CSS DSL directly into Elm. Awesome!

I was further intrigued by Evan's suggestion that type classes were in fact
a poor solution to this problem. I'm well aware that type classes are an
overused abstraction in Haskell that can cause lots of pain in unintended
ways, especially when using them for the sole purpose of reusing nice,
short function names.

This is exactly what a CSS DSL must do, however - we'd like to be able to
say both *"overflow: hidden" *and "border-style: hidden" in our DSL by
reaching for the same intuitive name *hidden* and just have everything
magically work. Sounds like exactly the difficult sort of modeling problem
that type classes seem *superficially* suitable, but are often not in
practice.

However, after looking up the venerable elm-css
 library and peeking around its
internals, I'm not sure I agree. The implementation is, in a word,
abstruse. The types that end-users have to see and interact with are highly
non-intuitive. There's a lot of data being slogged around at runtime to
satisfy the type checker. It's simply not a good abstraction. The DSL that
came out on the other end looks great, but at what cost?

For some context, here's how I'd proceed if I had to implement this in
Haskell with type classes.

Say we want to model the key *margin* which can have a value of *auto* or
some integer (simplifying a bit here). I'd write the following type class:

*  class Margin a where*
*margin :: a -> Style*

Then, I'd write two instances for the type class - one for my made-up type
*auto* and another for *Int*.

*  data Auto = Auto*

*  instance Margin Auto where*



*margin Auto = {- implementation... -}  instance Margin Int where
margin n = {- implementation... -}*

Here's what the final type of the *margin* combinator looks like:

*  margin :: Margin a => a -> Style*

and I could use it like so:

*  margin Auto*
*  margin 5*

Now, I'm not necessarily advocating this approach (DSL design is hard), but
there it is, for reference. I happen to share a lot of the sentiments
expressed in the podcast about type classes, but in this specific case,
they actually don't seem too bad. Compare the above with the machinery in
for margin that exists in elm-css:

  *type alias LengthOrAuto compatible =*


*{ compatible | value : String, lengthOrAuto : Compatible }*
*  margin : LengthOrAuto compatible -> Style*

*  auto :*
*{ lengthOrAuto : Compatible*
*, overflow : Compatible*
*, textRendering : Compatible*
*, flexBasis : Compatible*
*, lengthOrNumberOrAutoOrNoneOrContent : Compatible*
*, alignItemsOrAuto : Compatible*
*, justifyContentOrAuto : Compatible*
*, cursor : Compatible*
*, value : String*
*, lengthOrAutoOrCoverOrContain : Compatible*
*, intOrAuto : Compatible*
*}
*

Compatible, what? Some value field is a String? Keep in mind these type are
all visible to the user - necessarily so - so they can figure out how to
fit the pieces together. However, I don't think it's unreasonable to say
that the only way (or at least the *main *way) to use this library is to
shut your brain off and trust that if you get any compiler error, it's
because you did some illegal CSS thing. It's simultaneously exposes ugly
innards (type aliases) and yet resists when you try to grok what's going on
(Compatible is not exported, though for good reason).

It concede it's possible I have overlooked some part of the library where
the simple type class approach breaks down. But when attacked top-down (I
want the DSL to come out looking like *this *so I need to 

[elm-discuss] elm-css with type classes (a response to the Elm Town podcast)

2017-04-26 Thread Mitchell Rosen
Hello all! I am a (very) beginner Elm programmer, but I know a fair bit of 
Haskell. I listened to the most recent Elm Town podcast and was especially 
intrigued by the discussion around a novel use of record types to solve a 
real-world problem - embedding a nice CSS DSL directly into Elm. Awesome!

I was further intrigued by Evan's suggestion that type classes were in fact 
a poor solution to this problem. I'm well aware that type classes are an 
overused abstraction in Haskell that can cause lots of pain in unintended 
ways, especially when using them for the sole purpose of reusing nice, 
short function names.

This is exactly what a CSS DSL must do, however - we'd like to be able to 
say both *"overflow: hidden" *and "border-style: hidden" in our DSL by 
reaching for the same intuitive name *hidden* and just have everything 
magically work. Sounds like exactly the difficult sort of modeling problem 
that type classes seem *superficially* suitable, but are often not in 
practice.

However, after looking up the venerable elm-css 
 library and peeking around its 
internals, I'm not sure I agree. The implementation is, in a word, 
abstruse. The types that end-users have to see and interact with are highly 
non-intuitive. There's a lot of data being slogged around at runtime to 
satisfy the type checker. It's simply not a good abstraction. The DSL that 
came out on the other end looks great, but at what cost?

For some context, here's how I'd proceed if I had to implement this in 
Haskell with type classes.

Say we want to model the key *margin* which can have a value of *auto* or 
some integer (simplifying a bit here). I'd write the following type class:

*  class Margin a where*
*margin :: a -> Style*

Then, I'd write two instances for the type class - one for my made-up type 
*auto* and another for *Int*.

*  data Auto = Auto*

*  instance Margin Auto where*



*margin Auto = {- implementation... -}  instance Margin Int where
margin n = {- implementation... -}*

Here's what the final type of the *margin* combinator looks like:

*  margin :: Margin a => a -> Style*

and I could use it like so:

*  margin Auto*
*  margin 5*

Now, I'm not necessarily advocating this approach (DSL design is hard), but 
there it is, for reference. I happen to share a lot of the sentiments 
expressed in the podcast about type classes, but in this specific case, 
they actually don't seem too bad. Compare the above with the machinery in 
for margin that exists in elm-css:

  *type alias LengthOrAuto compatible =*


*{ compatible | value : String, lengthOrAuto : Compatible }*
*  margin : LengthOrAuto compatible -> Style*

*  auto :*
*{ lengthOrAuto : Compatible*
*, overflow : Compatible*
*, textRendering : Compatible*
*, flexBasis : Compatible*
*, lengthOrNumberOrAutoOrNoneOrContent : Compatible*
*, alignItemsOrAuto : Compatible*
*, justifyContentOrAuto : Compatible*
*, cursor : Compatible*
*, value : String*
*, lengthOrAutoOrCoverOrContain : Compatible*
*, intOrAuto : Compatible*
*} 
*

Compatible, what? Some value field is a String? Keep in mind these type are 
all visible to the user - necessarily so - so they can figure out how to 
fit the pieces together. However, I don't think it's unreasonable to say 
that the only way (or at least the *main *way) to use this library is to 
shut your brain off and trust that if you get any compiler error, it's 
because you did some illegal CSS thing. It's simultaneously exposes ugly 
innards (type aliases) and yet resists when you try to grok what's going on 
(Compatible is not exported, though for good reason).

It concede it's possible I have overlooked some part of the library where 
the simple type class approach breaks down. But when attacked top-down (I 
want the DSL to come out looking like *this *so I need to use *these 
language features*), I'm not seeing why one would prefer this row-types 
approach over type classes if both happened to exist in Elm.

Thanks for reading, and if this is the umpteenth post about type classes, I 
apologize. I figured at least the concept of type classes still relevant in 
this community, given they were briefly discussed on Elm Town just today. 
I'd love to hear any seasoned Elm-ers thoughts about row types as an 
abstraction mechanism, type classes or lack thereof, elm-css, or anything 
else that came to mind while reading over this post.

Mitchell

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