- λ> addTwoOccupation' (select [pr|UserId,Age,Occupation|] (frameRow ms 0))
-- {user id :-> 3, age :-> 26, occupation :-> "technician"}
-- #+END_EXAMPLE

-- We can unpack this type a bit to understand what is happening. A
-- ~Frames~ ~Record~ is a record from the ~Vinyl~ library, except that
-- each type has phantom column information. This metadata is
-- available to the type checker, but is erased during compilation so
-- that it does not impose any runtime overhead. What we are doing
-- here is saying that we will operate on a ~Frames~ row type, ~Record
-- rs~, that has an element ~Occupation~, and that deleting this
-- element works properly (i.e. the leftover fields are a proper
-- subset of the original row type). We further state -- with the
-- ~AsVinyl~ constraint -- that we want to work on the unadorned field
-- values, temporarily discarding their header information, with the
-- ~mapMethod~ function that will treat our richly-typed row as a less
-- informative ~Vinyl~ record.

-- We then peer through a lens onto the set of all unadorned fields other
-- than ~Occupation~, apply a function with a ~Num~ constraint to each of
-- those fields, then pull back out of the lens reattaching the column
-- header information on our way. All of that manipulation and
-- bookkeeping is managed by the type checker.

-- Lest we forget we are working in a typed setting, what happens if
-- the constraint on our polymorphic operation can't be satisfied by
-- one of the columns?

-- #+BEGIN_EXAMPLE
-- λ> addTwoOccupation (select [pr|Age,Occupation,Gender|] (frameRow ms 0))

-- <interactive>:15:1-16:
--     No instance for (Num Text) arising from a use of ‘addTwoOccupation’
--     In the expression:
--       addTwoOccupation
--         (select
--            (Proxy :: Proxy '[Age, Occupation, Gender]) (frameRow ms 0))
--     In an equation for ‘it’:
--         it
--           = addTwoOccupation
--               (select
--                  (Proxy :: Proxy '[Age, Occupation, Gender]) (frameRow ms 0))
-- #+END_EXAMPLE

-- This error message isn't ideal in that it doesn't tell us which
-- column failed to satisfy the constraint. Hopefully this can be
-- improved in the future!

-- * Escape Hatch

-- When you're done with ~Frames~ and want to get back to more
-- familiar monomorphic pastures, you can bundle your data up.

restInts :: (AllAre Int (UnColumn rs), AsVinyl rs)
         => Record (s :-> Text ': rs) -> (Text, [Int])
restInts (recUncons -> (h, t)) = (h, recToList t)

-- #+BEGIN_EXAMPLE
-- λ> res
restInts :: (AllAre Int (UnColumn rs), AsVinyl rs)
         => Record (s :-> Text ': rs) -> (Text, [Int])
restInts (recUncons -> (h, t)) = (h, recToList t)
restInts (recUncons -> (h, t)) = (h, recToList t)