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 <[email protected]
> <javascript:>> 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 [email protected] <javascript:>.
>> 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 [email protected].
For more options, visit https://groups.google.com/d/optout.