snix/users/Profpatsch/my-prelude/src/Divisive.hs
Profpatsch 444b67b010 feat(users/Profpatsch/my-prelude): add builder & divisible helpers
I’ve had enough of `show & stringToText` bullshit, let’s finally
create a trivial builder contravariant module that wraps
`Text.Builder` and `ByteString.Builder` and has a naming scheme that
does not collide with anything and that I can remember in my sleep.

Plus some experiments in making `Divisible` useful with `HasField`.

Change-Id: Ie25f78226d24eadf4c35353fe9db40b7683d82c3
Reviewed-on: https://cl.tvl.fyi/c/depot/+/12955
Tested-by: BuildkiteCI
Reviewed-by: Profpatsch <mail@profpatsch.de>
2025-01-05 21:00:11 +00:00

44 lines
1.3 KiB
Haskell

{-# LANGUAGE AllowAmbiguousTypes #-}
module Divisive where
import Data.Functor.Contravariant
import Data.Functor.Contravariant.Divisible
import GHC.Records (HasField (getField))
import Label
-- | Combine two divisibles into a struct with any two labelled fields.
divide2 ::
forall l1 l2 t1 t2 d r.
(Divisible d, HasField l1 r t1, HasField l2 r t2) =>
d t1 ->
d t2 ->
d r
divide2 = divide (\r -> (getField @l1 r, getField @l2 r))
-- | Combine two divisibles into a 'T2' with any two labelled fields.
dt2 ::
forall l1 l2 t1 t2 d.
(Divisible d) =>
d t1 ->
d t2 ->
d (T2 l1 t1 l2 t2)
dt2 = divide (\(T2 a b) -> (getField @l1 a, getField @l2 b))
-- | Combine three divisibles into a struct with any three labelled fields.
divide3 :: forall l1 l2 l3 t1 t2 t3 d r. (Divisible d, HasField l1 r t1, HasField l2 r t2, HasField l3 r t3) => d t1 -> d t2 -> d t3 -> d r
divide3 a b c = adapt >$< a `divided` b `divided` c
where
adapt r = ((getField @l1 r, getField @l2 r), getField @l3 r)
-- | Combine three divisibles into a 'T3' with any three labelled fields.
dt3 ::
forall l1 l2 l3 t1 t2 t3 d.
(Divisible d) =>
d t1 ->
d t2 ->
d t3 ->
d (T3 l1 t1 l2 t2 l3 t3)
dt3 a b c = adapt >$< a `divided` b `divided` c
where
adapt (T3 a' b' c') = ((getField @l1 a', getField @l2 b'), getField @l3 c')