purescript / purescript-record

Functions for working with records and polymorphic labels
BSD 3-Clause "New" or "Revised" License
70 stars 31 forks source link

Curry/partially apply a record #12

Closed chexxor closed 7 years ago

chexxor commented 7 years ago

@monoidmusician had a super-cool idea. A function which takes an n-field record as argument is like an n-arity function. If we can partially apply a function, we should be able to partially apply fields of a record.

It should work something like this:

-- If you have some function which takes a record as an argument...
f :: { field1 :: Int, field2 :: Int } -> Int
-- you could partially apply it.
curry f {field1: 1} :: { field2 :: Int } -> Int

Here's the snippet he pasted. He said it needs to be type-checked xD.

foreign import unsafeMergeImpl :: forall r1 r2 r.
  Record r1 -> Record r2 -> Record r

unsafeMerge :: forall r1 r2 r. Union r1 r2 r =>
  Record r1 -> Record r2 -> Record r

class CurryNamed
  (expected :: # Type)
  (given    :: # Type)
  (final    ::   Type)
  (step     ::   Type)
  | expected given final -> step
  where
    curryNamed ::
      (Record expected -> final) ->
      (Record given -> step)

instance curryNamed ::
  ( Union remaining given expected
  , RowToList remaining remainingRL
  , CurryNamedRL remainingRL expected remaining given final step
  ) => CurryNamed expected given final step
  where
    curryNamed = curryNamedRL (RLProxy :: RLProxy remainingRL)

class
  ( Union remaining given expected
  , RowToList remaining remainingRL
  ) <= CurryNamedRL
  (remainingRL :: RowList)
  (expected    ::  # Type)
  (remaining   ::  # Type)
  (given       ::  # Type)
  (final       ::    Type)
  (step        ::    Type)
  | remainingRL expected given final -> step remaining
  where
    curryNamedRL :: RLproxy remainingRL ->
      (Record expected -> final) ->
      (Record given -> step)

instance curryNamedNil ::
  TypeEquals expected given =>
  CurryNamedRL Nil expected () given final final
  where
    curryNamedRL _ = compose from

instance curryNamedCons ::
  ( ListToRow remainingRL remaining
  , Union remaining given expected
  , CurryNamed expected remaining final step
  ) => CurryNamedRL (Cons sym t rl) expected remaining given final step
  where
    curryNamedRL _ f g = curryNamed (f <<< flip unsafeMerge g)
paf31 commented 7 years ago

Sounds really cool and useful in some cases, but probably not something to include in this library, in my opinion.

chexxor commented 7 years ago

Yeah, can't say I disagree. :) The idea has been recorded here, so will close this. I'm sure someone will make a purescript-record-more library to hold this kind of thing.