I have a data type `NodeF atom a`

. I’d like to make two flavors of the this data type called `CharNodeF a`

and `TokenNodeF a`

. These would be equivalent to `NodeF Char`

and `NodeF String`

. Is there anyway to do that? Right now I’m writing out `(NodeF Char)`

wherever I need a `CharNodeF`

. Here’s some of the code:

```
data NodeF atom a
= Fraction { id :: Int, numerator :: Array a, denominator :: Array a }
| Atom { id :: Int, value :: atom }
derive instance charNodeFunctor :: Functor (NodeF Char)
instance showCharNodeF :: Show a => Show (NodeF Char a) where
show (Fraction {numerator, denominator}) = "(num:" <> (show numerator) <> ", den:" <> (show denominator) <> ")"
show (Atom {value, id}) = (show value) <> ":" <> (show id)
```

Ideally, you would use type aliases:

```
type CharNodeF a = NodeF Char a
type TokenNodeF a = NodeF String a
```

However, you cannot define type class instances for type aliases. This is a restriction the core contributors to the PS language want to drop in the future, but it hasn’t happened yet. Since you already have a `Functor`

instance for `NodeF Char`

, you’ll have to use newtypes:

```
newtype CharNodeF a = CharNodeF (NodeF Char a)
instance showCharNodeF :: Show a => Show (CharNodeF a) where
show (CharNodeF nodeFCharA) = case nodeFCharA of
Fraction {numerator, denominator} -> "(num:" <> (show numerator) <> ", den:" <> (show denominator) <> ")"
Atom {value, id} -> (show value) <> ":" <> (show id)
```

However, then you’ll deal with the newtype constructor wrapping/unwrapping boilerplate.

So, here’s the possible decisions you can make:

- choose to write ‘NodeF Char’ in type signatures a lot
- choose to write
`un CharNodeF charNodeFValue`

and/or `(CharNodeF nodeFCharA)`

in value-level terms / pattern matching a lot
- use type aliases and code without using type classes

2 Likes

Thank you for the reply. I think I stick with `NodeF Char`

for now. Looking forward to PS dropping that restriction on type aliases in the future.

This is a restriction the core contributors to the PS language want to drop in the future, but it hasn’t happened yet.

Is there a GitHub ticket I could upvote for this?

I don’t think it a good idea, automatically generating instances by something like `deriving via`

could be better.

By “dropping the restriction”, it would just be expanding the synonym. Synonyms are never nominal and will not ever affect instance dispatch.

1 Like

Here’s a concrete example of what Nate was talking about (or is at least my understanding of how it would work once implemented and merged):

```
data Original atom = Box String
type IndentBy5 = Original Five
type IndentBy2 = Original Two
instance showIndentBy0 :: Show IndentBy0 where
show (Box s) = s
instance showIdentityBy2 :: Show IndentBy2 where
show (Box s) = " " <> s
-- which "dealiases" / "expands the synonym" to
instance showIndentBy0 :: Show (Original Zero) where
show (Box s) = s
instance showIndentBy2 :: Show (Original Two) where
show (Box s) = " " <> s
-- Since the desugared types (Original Zero / Original Two)
-- are still different, these are valid instances,
-- just a lot easier to read and write.
type Same1 = Original One
type Same2 = Original One
instance showSame1 :: Show Same1 where
show (Box s) = "a" <> s
instance showSame2 :: Show Same2 where
show (Box s) = "b" <> s
-- which "dealiases" / "expands the synonym" to
instance showSame1 :: Show (Original One) where
show (Box s) = "a" <> s
instance showSame2 :: Show (Original One) where
show (Box s) = "b" <> s
-- Since the desugared types (Original One / Original One)
-- are the same, these are invalid instances and
-- will result in a compiler error.
```

well, sounds good. Currently it’s annoying to make instance for record types.