Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert joins into nested tuples #189

Closed
tomjaguarpaw opened this issue Aug 12, 2016 · 6 comments
Closed

Convert joins into nested tuples #189

tomjaguarpaw opened this issue Aug 12, 2016 · 6 comments

Comments

@tomjaguarpaw
Copy link
Owner

Migrated from: prowdsponsor/esqueleto#145 (comment)

@saurabhnanda This will blow your mind. Generalized grouping/nesting with group:

{-# LANGUAGE ExistentialQuantification #-}

import Lens.Micro
import Lens.Micro.Extras
import Data.Monoid
import Data.Map hiding (foldl', keys)
import Data.List (foldl')

data Entity a = Entity deriving (Ord, Eq)
data Download
data File
data URL
data Referrer
data Comment  
data User
data Post

groupBy' :: Ord b => (a -> b) -> (a -> c) -> [a] -> [(b, [c])]
groupBy' f g = toList . foldl' (\m kv -> insertWith (++) (f kv) [g kv] m) empty

data Group a r m =
  forall g. Ord g => Group { groupBy :: a -> g
                           , combine :: g -> r -> m
                           }

group :: Monoid m
      => Group a r m
      -> ([a] -> r)
      -> [a]
      -> m
group Group { groupBy = groupBy, combine = combine } groups =
  mconcat
  . over mapped (uncurry combine)
  . over (mapped._2) groups
  . groupBy' groupBy id

leaves = fmap

nest :: [(Entity Download, Entity File, Entity URL)]
     -> [(Entity Download, [(Entity File, [Entity URL])])]
nest = group (Group { groupBy = view _1
                    , combine = \x y -> [(x, y)]
                    })
       . group (Group { groupBy = view _2
                      , combine = \x y -> [(x, y)]
                      })
       $ leaves (view _3)

nest' :: [(Entity Download, Entity File, Entity URL)]
      -> Map (Entity Download) (Map (Entity File) [Entity URL])
nest' = group (Group { groupBy = view _1
                     , combine = \x y -> fromList [(x, y)]
                     })
        . group (Group { groupBy = view _2
                       , combine = \x y -> fromList [(x, y)]
                       })
        $ leaves (view _3)
@saurabhnanda
Copy link
Contributor

:)

I have another idea that will work well with nested records as well. I don't think one can keep avoiding nested records. What kind of JSON are you going to toss across the wire at the end of the request/response cycle?

@tomjaguarpaw
Copy link
Owner Author

I'm not sure I understand your question about JSON. Can you rephrase?

@saurabhnanda
Copy link
Contributor

I meant that in any web programming project, if you're trying to represent your data (which may be stored in an RDBMS) via a JSON API for building a UI on top of it, you'll most probably end up with a nested record structure in Haskell. So, we have to solve for that case. Is there any other way to do this without using nested records?

@saurabhnanda
Copy link
Contributor

saurabhnanda commented Aug 16, 2016

I tried my approach, and failed with nested records yet again. This is so frustrating.

http://lpaste.net/177548

Help would be appreciated.

@tomjaguarpaw
Copy link
Owner Author

You're trying to bite off a lot in one go.

  • You should write [Entity Url] -> [J.Url]
  • Use it to write [(Entity File, Entity Url)] -> [J.File] (probably with some help with one of my groupBy functions)
  • Use it to write [(Entity Download, Entity File, Entity Url)] -> [J.Download] (again with help from one of my groupBys)

@tomjaguarpaw
Copy link
Owner Author

Closing this. Feel free to contact me for any more help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants