Take a Quick Look at lists
I want to make a video about Quick Look. But I also want it to have more content than just the venerable head ids. So I thought a bit about what would make a nice use case for impredicative polymorphism. I came up with the idea of using forall a. Tree a -> Maybe a as the type of indices into a tree structure. I could now search in one tree for a value that satisfies a predicate returning a forall a. Tree a -> Maybe a to then retrieve a corresponding value (if the tree has the right shape) in another tree. Here is the code:
data Tree a
= Leaf a
| Node (Tree a) a (Tree a)
deriving (Show, Functor)
type TreeIndex = forall a. Tree a -> Maybe a
lookupTree :: forall a. (a -> Bool) -> Tree a -> Maybe TreeIndex
lookupTree p = go
where
go :: Tree a -> Maybe TreeIndex
go (Leaf x)
| p x = Just (\case Leaf y -> Just y
Node _ y _ -> Just y)
| otherwise = Nothing
go (Node left x right)
| p x = Just (\case Leaf y -> Just y
Node _ y _ -> Just y)
| otherwise = asum [go left, go right] -- (go left : go right : [])
(This doesn't work, as written, because the last line just returns the TreeIndex from the recursive call. But never mind this.)
(NB to GHC aficionados: asum is the same as GHC's firstJusts.)
What's sad is that the last line fails to type-check. However, if I remove the list argument and replace it with the commented-out cons-and-nil argument, all is well. This is because GHC doesn't take a Quick Look at lists. But it really should. And probably tuples, too.