Add a note on Final Tagless
This commit is contained in:
parent
cce60e0790
commit
0686c83ab2
1 changed files with 68 additions and 0 deletions
68
FinalTagless.md
Normal file
68
FinalTagless.md
Normal file
|
@ -0,0 +1,68 @@
|
|||
Below explanation is by Anupam Jain.
|
||||
|
||||
Here’s how to derive final tagless from first principles -
|
||||
|
||||
1. Final tagless is all about recursive data types.
|
||||
2. The usual way to encode recursive data types is to encode the recursion manually. For example -
|
||||
|
||||
```haskell
|
||||
data Tree = Leaf | Node Tree Tree
|
||||
```
|
||||
Here the definition for `Tree` mentions `Tree`. This is called the initial encoding.
|
||||
|
||||
3. A common trick for any recursion is to parametrise the recursive type.
|
||||
|
||||
```haskell
|
||||
data Tree a = Leaf | Node a a
|
||||
```
|
||||
|
||||
4. Once you parametrise, you can also convert this to a class.
|
||||
|
||||
```haskell
|
||||
class Tree t where
|
||||
leaf :: t
|
||||
node :: t -> t -> t
|
||||
```
|
||||
|
||||
This is called final encoding.
|
||||
|
||||
5. How would you add values to this tree structure? Consider a tree with values at leaf levels, you could use multi parameter type classes like below but that has its own can of worms -
|
||||
|
||||
```haskell
|
||||
class Tree t v where
|
||||
leaf :: v -> t
|
||||
node :: t -> t -> t
|
||||
```
|
||||
|
||||
One problem here is that the node function still has no information about the leaf values, which causes issues with type inference.
|
||||
|
||||
6. A better solution is to use higher order type classes and `tag` the type of the tree -
|
||||
|
||||
```haskell
|
||||
class Tree t where
|
||||
leaf :: forall v. -> t v
|
||||
node :: forall v. t v -> t v -> t v
|
||||
```
|
||||
|
||||
7. Now it’s possible to add things that only work on some types of trees, for example sum all the leaves of the tree that works only for Integer trees -
|
||||
|
||||
```haskell
|
||||
sum :: t Int -> Int
|
||||
```
|
||||
|
||||
This is the final tagless style.
|
||||
|
||||
8. Note that you can do the same thing with GADTs.
|
||||
|
||||
```haskell
|
||||
data Tree v where
|
||||
Leaf :: forall v. v -> Tree v
|
||||
Node :: forall v. Tree v -> Tree v -> Tree v
|
||||
```
|
||||
and
|
||||
|
||||
```haskell
|
||||
sum :: Tree Int -> Int
|
||||
```
|
||||
|
||||
But GADTs aren't in `Haskell98`, and were considered “advanced” when final tagless was proposed.
|
Loading…
Reference in a new issue