Quickest way to provide default values for a record of Nullable values?

elbear Today at 9:30 AM
I’m using purescript-node-url and its parse function returns a record of nullable strings. what’s the quickest way to pass a default string if a field has a null value?

chexxor 2 hours ago
Maybe…

x :: { a :: Nullable String }
z :: { a :: String }
z = x { a = x.a # toMaybe >>> (fromMaybe "some default value")  }

chexxor 2 hours ago
Otherwise could use ps-heterogeneous
https://pursuit.purescript.org/packages/purescript-heterogeneous/0.3.0

data DefaultVal = DefaultVal
instance defaultMapping ::
  (HasDefaultVal n) =>
  Mapping DefaultVal n String where
  mapping DefaultVal = hasDefaultVal
-- then
z :: { a :: String }
z = hmap DefaultVal y

chexxor 1 hour ago
@natefaubion Is using a HasDefaultVal type class constraint the best way to do this?
I think the only other way would be to write a handler for each field name rather than each field type.

natefaubion 1 hour ago
You can use MappingWithIndex

newtype DefaultFields r = DefaultFields { | r }

instance mappingDefaultFields_1 ::
  ( Row.Cons sym a rx r
  , IsSymbol sym
  ) =>
  MappingWithIndex (DefaultFields r) (SProxy sym) (Maybe a) a where
  mappingWithIndex (DefaultFields r) sym = fromMaybe (Record.get sym r)
else
instance mappingDefaultFields_2 ::
  MappingWithIndex (DefaultFields r) (SProxy sym) a a where
  mappingWithIndex _ _ = identity

defaulted ::
  forall r rin rout.
  HMapWithIndex (DefaultFields r) rin rout =>
  { | r } ->
  rin ->
  rout
defaulted r = hmapWithIndex (DefaultFields r)

defaultTest =
  defaulted { foo: 42, bar: "bar" }
    { foo: Nothing
    , bar: Just "wat"
    }

it’s basically just a zip

chexxor 3 minutes ago
Oh nice! That should also work for a record having Nullable a values, just by adding an else instance mappingDefaultFields_2 which is nearly identical to the Maybe instance right there.

natefaubion < 1 minute ago
Yeah, you could add another case for Nullable

chexxor < 1 minute ago
@natefaubion That seems really useful! Don’t even need to make the highly controversial class HasDefault a where hasDefault :: a! Instead, the default values are just specified at the defaulted function call! Well, it doesn’t solve exactly the same problem as that controversial class, but it allows for easier side-stepping of it in this case.

natefaubion < 1 minute ago
this also works for variants as well
which is kind of neat
if you have a Variant (foo :: Maybe Int) you can use defaulted with that
to turn it into Variant (foo :: Int)

chexxor 2 minutes ago
Oh wait, your algorithm doesn’t change Nullable a to a only when it’s null, does it?

natefaubion 1 minute ago
It uses fromMaybe
so if it’s Just then it uses what’s there, otherwise if its Nothing, it uses the default in the record

chexxor < 1 minute ago
Oh duh. It returns a partially applied function there

3 Likes