Skip to content

Instantly share code, notes, and snippets.

@safareli
Last active July 17, 2019 19:26
Show Gist options
  • Save safareli/596c5993362f7477c380a8e66a80d158 to your computer and use it in GitHub Desktop.
Save safareli/596c5993362f7477c380a8e66a80d158 to your computer and use it in GitHub Desktop.
SProxies
-- | This is module defines modified version `SProxies` and `mkSProxies` from [here][Row] ([depending on this][Utils]).
-- | That code was licensed with [Apache License 2.0][License]
-- |
-- | [Row] - https://github.com/thomashoneyman/purescript-halogen-formless/blob/55e2453f8e0d9169ec3cdccdd8cc09c0e289ffea/src/Formless/Transform/Row.purs#L61-L100
-- | [Utils] - https://github.com/thomashoneyman/purescript-halogen-formless/blob/55e2453f8e0d9169ec3cdccdd8cc09c0e289ffea/src/Formless/Internal/Transform.purs#L23-L35
-- | [License] - https://github.com/thomashoneyman/purescript-halogen-formless/blob/55e2453f8e0d9169ec3cdccdd8cc09c0e289ffea/LICENSE
module Type.SProxies
( SProxies
, SProxies'
, mkSProxies
, class MakeSProxies
, makeSProxiesBuilder
)
where
import Prelude
import Data.Identity (Identity)
import Data.Newtype (class Newtype)
import Data.Symbol (class IsSymbol, SProxy(..))
import Prim.Row as Row
import Prim.RowList as RL
import Record.Builder (Builder)
import Record.Builder as Builder
import Type.Proxy (Proxy(..))
import Type.Row (RLProxy(..))
-- | A type to collect constraints necessary to apply to prove that a record of
-- | SProxies is compatible with your type, which was constructed by some type
-- | constructor of form `# Type -> Type` (Record, Variant ...)
type SProxies t = ∀ container xs inputs row . SProxies' (Identity t) container xs inputs row
-- | A helper function to produce a record of SProxies given a type, to save
-- | you the boilerplate of writing them all out.
-- |
-- | ```purs
-- | type T = {foo :: Int, baz :: Int}
-- |
-- | prx :: SProxies T
-- | prx = mkSProxies (Proxy :: Proxy T)
-- |
-- | x :: SProxy "foo"
-- | x = prx.foo
-- | ```
mkSProxies
:: ∀ t container xs inputs row
. Proxy t
-> SProxies' (Identity t) container xs inputs row
mkSProxies _ = mkSProxies' (Proxy :: Proxy (Identity t))
-- | It's just common part of `mkSProxies` `SProxies` so we DRY.
type SProxies' t container xs inputs row
= Newtype t (container inputs)
=> RL.RowToList inputs xs
=> MakeSProxies xs row
=> Record row
-- | For `SProxies` to work, you want `xs row inputs` to be unsolved type
-- | variables and only way so far is to use Newtype, as it stops solving.
-- | Because of this, we not only have `mkSProxies'` and `SProxies'`, but
-- | we also have `mkSProxies` and `SProxies` so users don't have to
-- | use some newtype around there types. i.e. without `mkSProxies` and `SProxies`
-- | user would have to do this:
-- |
-- | ```purs
-- | type T = {foo :: Int, baz :: Int}
-- |
-- | prx :: SProxies (Identity T)
-- | prx = mkSProxies (Proxy :: Proxy (Identity T))
-- |
-- | x :: SProxy "foo"
-- | x = prx.foo
-- | ```
mkSProxies'
:: ∀ t container xs inputs row
. Proxy t
-> SProxies' t container xs inputs row
mkSProxies' _ = fromScratch builder
where
builder = makeSProxiesBuilder (RLProxy :: RLProxy xs)
-- | The class used to build up a new record of symbol proxies from an
-- | input row list.
class MakeSProxies (xs :: RL.RowList) (to :: # Type) | xs -> to where
makeSProxiesBuilder :: RLProxy xs -> FromScratch to
instance makeSProxiesNil :: MakeSProxies RL.Nil () where
makeSProxiesBuilder _ = identity
instance makeSProxiesCons
:: ( IsSymbol name
, Row.Cons name (SProxy name) from to
, Row.Lacks name from
, MakeSProxies tail from
)
=> MakeSProxies (RL.Cons name x tail) to where
makeSProxiesBuilder _ = first <<< rest
where
rest = makeSProxiesBuilder (RLProxy :: RLProxy tail)
first = Builder.insert (SProxy :: SProxy name) (SProxy :: SProxy name)
-- | Apply a builder that produces an output record from an empty record
fromScratch :: ∀ r. FromScratch r -> Record r
fromScratch = Builder.build <@> {}
-- | Represents building some output record from an empty record
type FromScratch r = Builder {} (Record r)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment