Answer:
Use sequenceRecord
on a structure with a “zippy” Applicative
instance. Array
s are too “explosive”, but ZipList
will work. A potential todo is to contribute ZipArray
to Data.Array
, but for now we’ll just convert with the toZ
function below. hmap
applies toZ
to each record field before the record is “sequenced” and then converted back into an array.
import Data.Array as A
import Data.List.Lazy as LL
import Data.List.ZipList (ZipList(..))
import Heterogeneous.Mapping (hmap)
import Record.Extra (sequenceRecord)
toZ :: Array Int -> ZipList Int
toZ = LL.fromFoldable >>> ZipList
myConversion :: MyRec1 -> Array MyRec2
myConversion =
hmap toZ >>> sequenceRecord >>> A.fromFoldable
If the input record types are heterogeneous rather than homogeneous (i.e. not all Array Int
) such as below:
type MyRec1Het =
{ a :: Array Int
, b :: Array Number
, c :: Array Int
}
type MyRec2Het =
{ a :: Int
, b :: Number
, c :: Int
It is tempting to generalize the toZ
function to:
toZHet :: forall a. Array a -> ZipList a
toZHet = LL.fromFoldable >>> ZipList
However this won’t work, and is explained in more detail in the purescript-heterogeneous docs.
The solution is this approach:
data ToZHet = ToZHet
instance toZHet :: Mapping ToZHet (Array a) (ZipList a) where
mapping _ = LL.fromFoldable >>> ZipList
myConversionHet :: MyRec1Het -> Array MyRec2Het
myConversionHet =
hmap ToZHet >>> sequenceRecord >>> A.fromFoldable
Testing:
rin :: MyRec1
rin =
{ a: [0, 1]
, b: [0, 1]
, c: [0, 1]
}
rinHet :: MyRec1Het
rinHet =
{ a: [0, 1]
, b: [0.0, 1.0]
, c: [0, 1]
}
main :: Effect Unit
main = do
log $ show rin
log $ show $ myConversion rin
log $ show rinHet
log $ show $ myConversionHet rinHet
Output:
{ a: [0,1], b: [0,1], c: [0,1] }
[{ a: 0, b: 0, c: 0 },{ a: 1, b: 1, c: 1 }]
{ a: [0,1], b: [0.0,1.0], c: [0,1] }
[{ a: 0, b: 0.0, c: 0 },{ a: 1, b: 1.0, c: 1 }]