Should there be a type constructor for an alias of an alias?

181 views
Skip to first unread message

Peter Damoc

unread,
Jun 22, 2016, 4:05:04 AM6/22/16
to Elm Discuss
This does not work:

type alias MainModel = { int : Int} 
  
type alias Model = MainModel 

init = Model 1

and I'm wondering if this is a bug or the expected behavior. 






--
There is NO FATE, we are the creators.
blog: http://damoc.ro/

Alex Lew

unread,
Jun 22, 2016, 4:57:30 PM6/22/16
to Elm Discuss
This would be useful to have, especially if it worked on type aliases with type arguments:

type alias Container a = { contents : a }
type
alias IntContainer = Container Int

myContainer
= IntContainer 3

-- Or even this, which would require some decisions about how what order the
-- record fields of `Managed Book` would be in.
type
alias Managed a = { a | managerId : Int }
type
alias Book = { title : String, author : String }
type
alias ManagedBook = Managed Book

harryPotter
= ManagedBook 50321 "Harry Potter" "JK Rowling"

Nick H

unread,
Jun 22, 2016, 5:51:00 PM6/22/16
to elm-d...@googlegroups.com
this is syntactically incorrect, because "Model" is not a type constructor.

the correct syntax would simply be

init: Model
init = { int = 1 }

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

Alex Lew

unread,
Jun 22, 2016, 6:02:07 PM6/22/16
to elm-d...@googlegroups.com
Normally, when you alias a record, Elm creates a “record constructor" automatically. See this note at the bottom of http://guide.elm-lang.org/types/type_aliases.html:

Note: When you create a type alias specifically for a record, it also generates a record constructor. So our User type alias will also generate this function:

User : String -> String -> String -> User
The arguments are in the order they appear in the type alias declaration. You may want to use this sometimes.

This is why it does work, in Peter’s example, to write MainModel 1. I think Peter’s question is whether this is intended to work for “an alias of an alias” too. I think there are useful reasons for this to be the case. In the example I posted, having `ManagedBook` be a constructor would allow you to more easily write, e.g., a JSON Decoder for a ManagedBook. But I can see arguments both ways.


You received this message because you are subscribed to a topic in the Google Groups "Elm Discuss" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/elm-discuss/5Lw3D0DmlCo/unsubscribe.
To unsubscribe from this group and all its topics, send an email to elm-discuss...@googlegroups.com.

Nick H

unread,
Jun 22, 2016, 6:07:19 PM6/22/16
to elm-d...@googlegroups.com
Whaaaat. That is crazy. I had no idea Elm let you do that.

Max Goldstein

unread,
Jun 22, 2016, 6:58:46 PM6/22/16
to Elm Discuss
Record constructors from aliases are one of Elm's few "magic" features...

Peter Damoc

unread,
Jun 23, 2016, 2:18:00 AM6/23/16
to Elm Discuss
Alex,  your use-case is way more interesting and useful than mine. 

What I was trying to do was more like a simple rename. 
I put the MainModel in a different file because it needed to be imported in different places and I ended up with a circular dependency but I wanted to keep referring to it as Model in the original location.  



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

Nick H

unread,
Jul 4, 2016, 2:07:09 PM7/4/16
to elm-d...@googlegroups.com
I thought of a potential advantage of keeping the behavior as it currently is: it gives library authors a way of making record types opaque.

Consider a union type.

type Foo = FooA Float | FooB Int | FooC

If an author wants the type constructors as part of the public API, their module header looks like this:

module FooModule exposing (Foo(..))

But if they wants to hide the type constructors, they can change it to this:

module FooModule exposing (Foo)

A record type always exposes its definition & constructors:

module FooModule exposing (PublicFoo)
type alias PublicFoo = { a : Float }

But using the behavior that Peter asks about, an author can alias the record and hide its "record-ness" from library users:

module FooModule exposing (PublicFoo)
type alias PublicFoo = PrivateFoo
type alias PrivateFoo = { a : Float }


Reply all
Reply to author
Forward
0 new messages