Skip to content

Instantly share code, notes, and snippets.

@MichaelBaker
Last active August 29, 2015 14:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MichaelBaker/a9bc29d188494504e7d9 to your computer and use it in GitHub Desktop.
Save MichaelBaker/a9bc29d188494504e7d9 to your computer and use it in GitHub Desktop.

I'm experimenting with some ideas and I think one of the problems I have could be solved with lenses, but it doesn't seem to work how I expect it to when I try to implement it.

I want to create a tree of data structures, where each node stores a lens that goes from the root of the tree down to that node. Here is a conceptual image. The idea in that image is that the color of the lens matches the color of the path that it represents through the tree.

Here is an example of a tree shaped data structure without storing the path lenses at the nodes:

{-# LANGUAGE TemplateHaskell #-}

import Control.Lens

data Child a = Child { _value :: a } deriving (Show)
data Root = Root { _child1 :: Child Int, _child2 :: Child Char } deriving (Show)

makeLenses ''Child
makeLenses ''Root

main = do
  let tree = Root (Child 1) (Child 'a')
  print $ tree ^. child2 . value

Here is the same example, but now I've added a separate data type to represent the nodes explicitly and I again use a lense to traverse the tree.

{-# LANGUAGE TemplateHaskell #-}

import Control.Lens

data Child a  = Child { _value :: a }
data Root     = Root  { _child1 :: Tree (Child Int), _child2 :: Tree (Child Char) }
data Tree a   = Tree  { _content :: a }

makeLenses ''Child
makeLenses ''Root
makeLenses ''Tree

main = do
  let c1   = Tree (Child 1)
      c2   = Tree (Child 'a')
      root = Tree (Root c1 c2)
  print $ root ^. content . child1 . content . value
  print $ root ^. content . child2 . content . value

Finally, this is what I would like to end up with:

{-# LANGUAGE TemplateHaskell, NoMonomorphismRestriction #-}

import Control.Lens

data Child a  = Child { _value :: a }
data Root a b = Root { _child1 :: Tree a (Child Int), _child2 :: Tree b (Child Char) }
data Tree c a = Tree { context :: c, _content :: a }

makeLenses ''Child
makeLenses ''Root
makeLenses ''Tree

main = do
  let c1   = Tree (content . child1 . content) (Child 1)
      c2   = Tree (content . child2 . content) (Child 'a')
      root = Tree (content) (Root c1 c2)
  print $ root ^. (context c1) . value

But this implementation give me this error on the line with the print statement:

No instance for (Functor f2) arising from a use of ‘root’
The type variable ‘f2’ is ambiguous
Note: there are several potential instances:
  instance Functor ((,) a) -- Defined in ‘GHC.Base’
  instance Functor ((->) r) -- Defined in ‘GHC.Base’
  instance Functor IO -- Defined in ‘GHC.Base’
  ...plus 11 others
In the first argument of ‘(^.)’, namely ‘root’
In the first argument of ‘print’, namely
  ‘(root ^. (c1 ^. context) . value)’
In a stmt of a 'do' block: print (root ^. (c1 ^. context) . value)

I don't really understand what is expected of me here. Any advice?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment