Recursive type clarification

Hi there,
I’m trying to work out how to make my first elm app and i’m going through some examples on web. I have encountered this definition

type Avatar
    = Avatar (Maybe String)

how does one read this and what does it mean? does this pattern have specific name?

Hello there!

What you are looking at is what we call a Custom Type. They can be recursive, but this one is not.

A way to read it goes something like this. type Avatar is saying I am creating a new type called "Avatar’. = Avatar (Maybe String) is saying a few things. First it is saying we only have one “variant”. Next it is saying what the name of the type constructor is (in this case its Avatar but it does not need to match the type name). And lastly it is saying that Avatar “holds” (Maybe String)

Id recommended checking out the link to Custom Types above, and also tossing that type into elm repl and playing around with it :slight_smile:.

I would read it like "type Avatar has a constructor called Avatar that takes Maybe String as an argument.

So it’s similarly to object-oriented languages, where the class constructor has the same name as the class. In java I would write: Avatar avatar = new Avatar(stringOrNull)

1 Like

so if i understand correctly here, type definition is collection of functions that result in that type. In other words all the way in which type can be constructed.

in this case it would be only one function (Maybe String) -> Avatar, however i still have a problem with "visualizing " shape of Avatar.

my formal FP is obviously not that strong so i would appreciate very much if someone can point to some resources where i could better understand mechanism, how is elm tracking which constructor is used and such.

thank you very much for help so far

Yes. exatly. Though it does not have to be functions.

Let’s look at Bool for a sec:

type Bool
  = True
  | False

So Bool can either be True or False. (The symobl | is read as “or”) That’s the structure of Bool.

Where as for Maybe a the definiton is

type Maybe a
  = Just a
  | Nothing

So the structure behind it is either Nothing, or (Just something).

Just itself is also a function. Just:a -> Maybe So depending on how you look on it. its either “How do i construct this type?” or “What shape can this type be?”.


Now back to the Avatar.

type MyAvatar
  = AvatarByName (Maybe String)

So Avatar is defined by its name. So the structure of the Avatar is its name.

1 Like

would than True and False be constructors for Bool?

Yes.

You might ask “arn’t constructors always functions?” and you are right. But functions don’t need arguments.

You could say “True is a function with no argument”. If you come from typescript, this might look familiar:

type Bool = "True" | "False"

function True(){return "True"}

function False(){return "False"}

In Elm functions with no arguments and constants are the same thing.

1 Like

That makes sense.

In other languages types are collections of things, usually other types and from this is seems that in elm one construct the type in “reverse”, meaning you declare pathways in which you arrive to the type.

@Lucas_Payr thak you once agan

Yeah. I think you got it. But I want to give one more example to really show what’s happening under the hood:

type Avatar
  = Guest
  | Regular String
  | Admin {name: String, role:String}

Let’s try to implement the same type in Typescript:

type AvatarVariant = "Guest" | "Regular" | "Admin"

interface Avatar { variant : AvatarVariant }

interface Guest extends Avatar {}
interface Regular extends Avatar {name:String}
interface Admin extends Avatar {
  name:String;
  role:String;
}

function Guest() : Guest {
  return {variant : "Guest"}
}

function Regular(name:String) : Regular {
  return {variant: "Regular", name: name}
}

function Admin(name:String,role:String) : Admin {
  return {variant: "Admin", name: name, role: role} 
}
1 Like

@Lucas_Payr thank you once again this is very helpful!

I haven’t seen an actual recursive type yet in this thread, so thought I would give an example of one whilst hopefully not causing any confusion… Recursive types are very useful for building data structures.

You could define your own list type like this:

type MyList a
    = Nil
    | Cons a (MyList a)

Note that the type itself (MyList) appears in constructor argument position under Cons.

Also worth noting that you can only make recursive types in Elm, and you cannot make a recursive type alias:

type alias MyList a =
    { cons : Maybe (a, MyList a) }

-- ALIAS PROBLEM ---------------------------------------------------------- REPL

This type alias is recursive, forming an infinite type!

2| type alias MyList a =
              ^^^^^^
When I expand a recursive type alias, it just keeps getting bigger and bigger.
So dealiasing results in an infinitely large type! Try this instead:

    type MyList a =
        MyList
            { cons : Maybe ( a, MyList a ) }

Hint: This is kind of a subtle distinction. I suggested the naive fix, but I
recommend reading <https://elm-lang.org/0.19.1/recursive-alias> for ideas on how
to do better.


1 Like

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.