add recmapZipOnto fn family

recmapZipOnto functions respect Terminal types
This commit is contained in:
Emile Clark-Boman 2026-01-28 12:08:47 +10:00
parent d7224d5074
commit f2c7c04e2c

View file

@ -19,6 +19,12 @@
Some Some
None None
; ;
inherit
(this.terminal)
isTerminal
unwrapTerminal
;
in rec { in rec {
# getAttrAt :: [String] -> Attrs -> Maybe a # getAttrAt :: [String] -> Attrs -> Maybe a
# Given an attribute set path as a list of strings, # Given an attribute set path as a list of strings,
@ -45,21 +51,33 @@ in rec {
# recmapFrom :: [String] -> ([String] -> Attrs -> a) -> Attrs -> a | Attrs a # recmapFrom :: [String] -> ([String] -> Attrs -> a) -> Attrs -> a | Attrs a
# Alternative to mapAttrsRecursiveCond # Alternative to mapAttrsRecursiveCond
# Allows mapping directly from a child path # Allows mapping directly from a child path
recmapFrom = path: f: T: recmapCondFrom = path: cond: f: T: let
if isAttrs T delegate = path': recmapCondFrom path' cond f;
then mapAttrs (attr: leaf: recmapFrom (path ++ [attr]) f leaf) T in
if isAttrs T && cond path T
then T |> mapAttrs (attr: leaf: delegate (path ++ [attr]) leaf)
else f path T; else f path T;
# recmap :: ([String] -> Attrs -> a) -> Attrs -> a | Attrs a # recmap :: ([String] -> Attrs -> a) -> Attrs -> a | Attrs a
recmap = recmapFrom []; recmapCond = recmapCondFrom [];
recmapZipOntoCondFrom = path: cond: f: dst: src: let
zip = f': path': dstLeaf: f' path' dstLeaf (getAttrAt path' src);
in
dst
|> recmapCondFrom path (zip cond) (zip f);
recmapZipOntoCond = recmapZipOntoCondFrom [];
projectOnto = dst: src: projectOnto = dst: src:
dst src
|> recmap |> recmapZipOntoCond
(path: dstLeaf: let (path: dstLeaf: srcLeaf: ! isTerminal dstLeaf)
srcLeaf = getAttrAt path src; (path: dstLeaf: srcLeaf:
in
if isSome srcLeaf if isSome srcLeaf
then unwrapMaybe srcLeaf then unwrapMaybe srcLeaf
else dstLeaf); else if isTerminal dstLeaf
then unwrapTerminal dstLeaf
else dstLeaf)
dst;
} }