-
Notifications
You must be signed in to change notification settings - Fork 662
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature Request: Arbitrary (First-order) Datatypes in Ports #490
Comments
Totally support this and I've already given it some thought, so just some First, in Personally, I don't like the fact the null equates with Maybe. I would As far as the serialization scheme, I noticed that you essentially chose On Wed, Feb 5, 2014 at 6:51 PM, Max S. New [email protected] wrote:
|
My overall feeling on this are that, because elm is a strict language, all non-lambda types should have default serialization built in, and thus could all be used in ports. |
One small problem I see in your example: Without type annotations, the type variable a, in both the type of x and the type of y, is indeterminate. I point this out mainly to say that, if there are free variables in a type, then that type should not be serializable. |
Oh woops, I meant to use the data Foo a = Bar a
| Baz (Foo a) Int This should work: port out : Signal (Foo String)
port out = constant <| Bar "Work!" producing { _ctor: "Bar", _0: "Work!" } but this should obviously be an error: port out : Signal ([a] -> a)
port out = contant head This is already handled to some extent since Maybe/List are serializable. |
I'd be more inclined to use the Let's do some examples to see on how it looks: switch(value.ctor) { ... }
switch(value.constructor) { ... } // collides with built-in JS name?
value._0
// I feel like this is not a thing that is named, but
value.params[0]
value.values[0]
// or maybe
value.v0
value.p0
value.a0
value[0] // you can use numbers as field names! :O No idea! As it is, you don't need to have a full list of constructors to do any of this. Although, it could be very valuable to have such a list because generated JS could switch on integers instead of strings, which should be significantly faster: switch (x.ctor) {
case "Just":
case "Nothing":
}
// possibly faster version
switch (x.ctor) {
case 0:
case 1:
} I think this kind of optimization is not a good idea right now. No one will notice speed gains in this realm, and it'll make things harder to maintain and make generated code harder to read. |
Why not just use an array, using the first element for ctor?
|
@JohnNilsson, that's actually how things were represented early on in the generated code :) I think it was slower, but I don't think that's the point of this API. switch(foo[0]) {
case "Baz":
return foo[1] + foo[2];
case "Bar":
} Any opinions on the looks of this? (with your JS cap on) |
Maybe we should have a more realistic example and do a bunch of gists? |
Here is the code for the program I was writing: https://gist.github.com/maxsnew/8855176 . |
I'm really just hoping for ADT compatibility with Data.Aeson.TH, which Let's say we have: data Foo = Bar Int String Elm internals currently look like { "ctor" : "Bar", "_0" : 5, "_1" : "baz" } Data.Aeson.TH has three modes for ADTs. TaggedObject looks like { "tag" : "Bar", "contents" : [ 5, "baz" ] } ObjectWithSingleField looks like { "Bar" : [ 5, "baz" ] } TwoElemArray looks liks [ "Bar", [ 5, "baz" ] ] On Thu, Feb 6, 2014 at 7:15 PM, Max S. New [email protected] wrote:
|
Cool, @maxsnew that examples helps me :) I like the names "tag" and "contents" a lot! That is much more intuitive for me when I think of them as JS data structures. I think the ObjectWithSingleField always seems like a cool and great idea until you actually try to use it in JS and find that it's a decent pain in the ass (this is the key problem with the type format in generated documentation). So I would currently lean towards the TaggedObject style. |
As for the issue of "should It may make sense to have a type alias |
Yes I agree that TaggedObject is the nicest pattern. I don't think there I've backtracked on my opinion of Maybe; I think it does make sense to have On Sat, Feb 8, 2014 at 10:19 AM, Evan Czaplicki [email protected]:
|
Okay, so the main goal of this issue is: Get conversion with the TaggedObject style. The subgoal is: Optimize case expressions to use extra information to generate switches on integers. I think there is a hack to do this :) When you generate constructors for an ADT, you also generate some helper structures in JS. data Either a b = Left a | Right b would generate the normal var Either = { Left : 0, Right : 1, schemas : [ ... ] }; And from there you use |
Hi, I was wondering what the status of this feature is. I made a post on the mailing list that is related to this. I can potentially contribute towards this if it would help accelerate this feature. By the way, I've benchmarked switching on strings vs. inlining integers, and surprisingly strings seems to do better. I ran this in chrome 35 and strings are twice as fast: Average string time: 0.0010951002826914192
|
Just talked with @michaelbjames about working on this feature. These benchmarks appear to confirm your results, which is very confusing to me. Perhaps people switch on strings more often? In any case, let's not do that part of this then. You are welcome to take a look, but keep @michaelbjames up to date on what you find. I think it's a trickier to implement than it sounds. |
I remember making a jsperf test for this int vs string switching a long time ago, and I remember being surprised that strings were faster. It's apparently been this way for quite a while. |
Ok, I'll try to get in contact with @michaelbjames about working on this. |
+1 What is the status of this? I would advise first implementing, then optimizing it. :) |
As of now, a workaround is to pass Json.Values through ports and Json.Decode/Encode them. |
I'm a bit late to the party here, but has anyone considered exposing (and mandating the use of) explicit constructor functions? For example:
I see a few benefits to this:
Thoughts? |
I pitched an idea to Evan last week which boils down to registering destructors (in-port) and constructors (out-port) for arbitrary representations of variant types. We agreed that I'd write it up here to get some feedback. The main motivation is to arrive at a unified approach that subsumes currently port-compatible ADTs while allowing arbitrary data representations outside of Elm. This picks up on @rtfeldman's proposal. I very much tried to think with my JS cap on: How might I want to deal with this data in a JS codebase? (Hence trying to avoid Credo:
Benefits:
I'll reuse the example from above: data Foo a = Bar a
| Baz (Foo a) Int Let's assume that in my JS I represent those as (assuming { kind: 'Bar', size: '40sqm' }
{ kind: 'Baz', bar: { ... }, rooms: 5 } Other encodings abound, e.g. OOP style. Destructing Outside Representations (in-ports)port : Signal (Foo String) The basic idea for conversion at an in-port with type So in this case, for whatever outside representation OuterFoo String
-> (String -> Foo String) -- Bar
-> (Foo String -> Int -> Foo String) -- Baz
-> Foo String for example suppose the following function is registered for function fooIn(val, Bar, Baz) {
switch (val.tag) {
case 'Bar': return Bar(val.size);
case 'Baz': return Baz(val.bar, val.rooms);
}
}
What does
What does
What happens with the return value of
Note that this construction process is recursive, that is, nested ADTs can be sent through ports. Constructing Outside Representations (out-ports)The idea is similar but now the converter is called with a tag (probably a string?) and the data, from which it constructs whichever representation desired. Converter RegistrationA default converter (e.g. from and to TaggedObject) can be used when no converter is registered for a type. Converters can be registered globally for all types and/or per type. Because ADTs may appear nested inside ADTs or records, we need to do one of two things:
BuiltinsThe Elm runtime could make use of this approach to register a TaggedObject converter as default, while pre-registering special converters for builtin types such as I have more details, but this is too long alreay. (Sorry!) What do you think? |
I am trying to clean up the issues on these repos. My goal is for issues on repos like The idea is that it doesn't super matter where the proposal is opened, but we should collect related ideas in certain places so we can look at them as a collection of issues and find a coherent solution that addresses them all as much as possible. So I'm gonna close this and reference elm-lang/elm-plans#17 which is collecting a bunch of port problems. If there is more to say about this idea, we should continue on this thread. The fact that is closed is more about decluttering stuff! |
This makes it more difficult to send the model through a port for serialization, so I ripped that feature out. It seems like this won't be easy until there is a solution to elm/compiler#490
Hello, What is the status of this? elm-lang/elm-plans#17 is still open with no status, but the repo is "deprecated"... Thanks, |
@evancz what is the progress on this |
This seems pretty simple to implement:
then
x
andy
could be serialized to the following javascript (field names could easily be something else):The only problem I see with this is that the serialization of
Maybe
would be inconsistent with this.Right now it's actually impossible to serialize a Sum type. Even if we're unsure about doing this in general, we definitely need to at least support the
Either
type. Currently I'm doing the following to get around this limitationwhere I ignore the 2nd value if the first one is non-null, but this is obviously suboptimal.
The text was updated successfully, but these errors were encountered: