This library exploits the underling representation of Record
and Variant
based types when they are homogeneous (all fields / cases have the same type) to provide a convenient instances for them (like Functor
, Apply
, Foldable
, Traversable
).
The core type is:
newtype Homogeneous (row ∷ # Type) a = Homogeneous (Foreign.Object a)
row
provides information about the structure of the Record
but a
is the underling type of the values in it. The "structure preserving" row is filled with Void
type for clarity. "Smart construction" is done by Foreign.Object.fromHomogeneous
which is just unsafeCoerce
underneath. Deconstruction (Record.Homogeneous.fromHomogeneous
) is yet another safe unsafeCoerce
alias :-P
Given the above we can provide (by mainly newtype derving from the Object
) many instances for this type like: Traversable
, Foldable
, Monoid
. There is also an Applicative
instance (inspired by instance from sized-vectors
).
Imports are required as we generate tests from this docs.
module Test.README where
import Prelude
import Data.Homogeneous.Record (homogeneous, fromHomogeneous) as Homogeneous.Record
import Effect (Effect)
import Test.Assert (assert)
Let's create two records. The first is our data record the second one (created with pure
) is a record full of functions (identical in this case _ * 2
):
recordInstances :: Effect Unit
recordInstances = do
let
r = { one: 1, two: 2, three: 3 }
multiply = pure (_ * 2)
To use instances from Homogeneous.Record
we need to wrap our record using a smart constructor homogeneous
. To go back we unwrap it using fromHomogeneous
. Both functions are really "cheap" underneath.
hr = Homogeneous.Record.homogeneous r
o = multiply <*> hr
r' = Homogeneous.Record.fromHomogeneous o
assert (r' == { one: 2, two: 4, three: 6 })
Of course we have others instances at hand too:
assert
((Homogeneous.Record.fromHomogeneous <<< map show $ hr) == { one: "1", two: "2", three: "3" })
What is quite a nice about this newtype
approach is that underling machinery (we deriving nearly all instances) is really simple and efficient based on Foreign.Object
.
The core type is:
newtype Homogeneous (row ∷ # Type) a = Homogeneous (VariantRep a)
What this type gives us is a Comonad
instance which allows us to extract
a
value from any homogeneous Variant
easily. Additionally we have extend
which together with map
and toVariant
can be probably useful to simplify repeated chain operations on a given variant.