diff --git a/hydra-typescript.cabal b/hydra-typescript.cabal
--- a/hydra-typescript.cabal
+++ b/hydra-typescript.cabal
@@ -5,7 +5,7 @@
 -- see: https://github.com/sol/hpack
 
 name:           hydra-typescript
-version:        0.17.2
+version:        0.17.3
 synopsis:       Hydra's TypeScript coder: emit TypeScript source from Hydra modules
 description:    Hydra is an implementation of the LambdaGraph data model, which takes advantage of an isomorphism between labeled hypergraphs and typed lambda calculus: in Hydra, "graphs are programs, and programs are graphs". TypeScript support for Hydra
 category:       Data
@@ -40,6 +40,6 @@
   build-depends:
       base >=4.19.0 && <4.22
     , containers >=0.6.7 && <0.8
-    , hydra-kernel ==0.17.2
+    , hydra-kernel ==0.17.3
     , scientific >=0.3.7 && <0.4
   default-language: Haskell2010
diff --git a/src/main/haskell/Hydra/TypeScript/Coder.hs b/src/main/haskell/Hydra/TypeScript/Coder.hs
--- a/src/main/haskell/Hydra/TypeScript/Coder.hs
+++ b/src/main/haskell/Hydra/TypeScript/Coder.hs
@@ -176,7 +176,7 @@
           bigIntCall = \txt -> tsCall (tsExprIdent "BigInt") [
                 strLit txt]
       in case lit of
-        Core.LiteralBinary v0 -> strLit (Literals.binaryToString v0)
+        Core.LiteralBinary v0 -> strLit (Literals.binaryToBase64 v0)
         Core.LiteralBoolean v0 -> boolLit v0
         Core.LiteralDecimal v0 -> numLit (Literals.bigintToInt64 (Literals.decimalToBigint v0))
         Core.LiteralString v0 -> strLit v0
@@ -239,7 +239,7 @@
             varExpr =
                     Optionals.cases (Names.moduleNameOf v0) (tsExprIdent local) (\ns -> Logic.ifElse (Equality.equal (Packaging.unModuleName currentNs) (Packaging.unModuleName ns)) (tsExprIdent local) (
                       let nsSegs = Lists.drop 1 (Strings.splitOn "." (Packaging.unModuleName ns))
-                          alias = Strings.cat2 "$mod_" (Strings.intercalate "_" nsSegs)
+                          alias = Strings.concat2 "$mod_" (Strings.join "_" nsSegs)
                       in (tsMember (tsExprIdent alias) local)))
         in (Optionals.cases (Lexical.lookupPrimitive g v0) varExpr (\prim ->
           let isZeroArityEffect =
@@ -271,7 +271,7 @@
                       let idx = Pairs.first acc
                           pats = Pairs.second acc
                           raw = Names.localNameOf pn
-                          uniq = Logic.ifElse (Equality.equal raw "_") (Strings.cat2 "_" (Literals.showInt32 idx)) raw
+                          uniq = Logic.ifElse (Equality.equal raw "_") (Strings.concat2 "_" (Literals.showInt32 idx)) raw
                           pat = tsTypedIdent (Formatting.sanitizeWithUnderscores Language.typeScriptReservedWords uniq) Syntax.TypeExpressionAny
                       in (Math.add idx 1, (Lists.concat2 pats [
                         pat]))) (0, []) fsLParams
@@ -298,14 +298,14 @@
               let headExpr = encodeTerm cx g currentNs headTerm
               in headExpr) (
               let fname = Formatting.sanitizeWithUnderscores Language.typeScriptReservedWords (Core.unName (Core.projectionFieldName v1))
-                  firstA = Optionals.fromOptional (tsExprIdent "undefined") (Lists.maybeHead encArgs)
+                  firstA = Optionals.withDefault (tsExprIdent "undefined") (Lists.head encArgs)
                   restA = Lists.drop 1 encArgs
                   fieldExpr = tsMember firstA fname
               in (Logic.ifElse (Lists.null restA) fieldExpr (tsCall fieldExpr restA)))
             Core.TermUnwrap _ -> Logic.ifElse (Lists.null encArgs) (
               let headExpr = encodeTerm cx g currentNs headTerm
               in headExpr) (
-              let firstA = Optionals.fromOptional (tsExprIdent "undefined") (Lists.maybeHead encArgs)
+              let firstA = Optionals.withDefault (tsExprIdent "undefined") (Lists.head encArgs)
                   restA = Lists.drop 1 encArgs
                   valueExpr = tsMember firstA "value"
               in (Logic.ifElse (Lists.null restA) valueExpr (tsCall valueExpr restA)))
@@ -511,8 +511,8 @@
           let lname = Formatting.capitalize (Names.localNameOf v0)
           in (Optionals.cases (Names.moduleNameOf v0) (Right (tsNamedType lname)) (\ns -> Logic.ifElse (Equality.equal (Packaging.unModuleName currentNs) (Packaging.unModuleName ns)) (Right (tsNamedType lname)) (
             let nsSegs = Lists.drop 1 (Strings.splitOn "." (Packaging.unModuleName ns))
-                typeAlias = Strings.cat2 "$type_" (Strings.intercalate "_" nsSegs)
-            in (Right (tsNamedType (Strings.cat [
+                typeAlias = Strings.concat2 "$type_" (Strings.join "_" nsSegs)
+            in (Right (tsNamedType (Strings.concat [
               typeAlias,
               ".",
               lname]))))))
@@ -596,7 +596,7 @@
 -- | Keep only names whose module differs from the current module's
 filterNonLocalNames :: Packaging.ModuleName -> S.Set Core.Name -> S.Set Core.Name
 filterNonLocalNames currentNs names =
-    Sets.fromList (Optionals.cat (Lists.map (\n -> Optionals.cases (Names.moduleNameOf n) Nothing (\nameNs -> Logic.ifElse (Equality.equal (Packaging.unModuleName currentNs) (Packaging.unModuleName nameNs)) Nothing (Just n))) (Sets.toList names)))
+    Sets.fromList (Optionals.givens (Lists.map (\n -> Optionals.cases (Names.moduleNameOf n) Nothing (\nameNs -> Logic.ifElse (Equality.equal (Packaging.unModuleName currentNs) (Packaging.unModuleName nameNs)) Nothing (Just n))) (Sets.toList names)))
 
 -- | Walk an application spine, returning the innermost head term and its arguments in application order
 flattenApplication :: Core.Term -> (Core.Term, [Core.Term])
@@ -671,7 +671,7 @@
 importsToText kind currentNs names =
 
       let pairs =
-              Optionals.cat (Lists.map (\n -> Optionals.cases (Names.moduleNameOf n) Nothing (\ns -> Logic.ifElse (Equality.equal (Packaging.unModuleName currentNs) (Packaging.unModuleName ns)) Nothing (Just (ns, n)))) (Sets.toList names))
+              Optionals.givens (Lists.map (\n -> Optionals.cases (Names.moduleNameOf n) Nothing (\ns -> Logic.ifElse (Equality.equal (Packaging.unModuleName currentNs) (Packaging.unModuleName ns)) Nothing (Just (ns, n)))) (Sets.toList names))
           transformLocal =
                   \s -> Logic.ifElse (Equality.equal kind "type") (Formatting.capitalize s) (Formatting.sanitizeWithUnderscores Language.typeScriptReservedWords s)
           importKeyword = Logic.ifElse (Equality.equal kind "type") "import type" "import"
@@ -680,30 +680,31 @@
                     let ns = Pairs.first p
                         n = Pairs.second p
                         local = transformLocal (Names.localNameOf n)
-                        existing = Optionals.fromOptional [] (Maps.lookup ns acc)
+                        existing = Optionals.withDefault [] (Maps.lookup ns acc)
                     in (Maps.insert ns (Lists.cons local existing) acc)) Maps.empty pairs
           currentSegs = Lists.drop 1 (Strings.splitOn "." (Packaging.unModuleName currentNs))
           currentDepth = Lists.length currentSegs
           currentIsTest =
-                  Logic.and (Logic.not (Lists.null currentSegs)) (Equality.equal (Optionals.fromOptional "" (Lists.maybeHead currentSegs)) "test")
-          baseUpPrefix = Logic.ifElse (Equality.equal currentDepth 1) "./" (Strings.cat (Lists.replicate (Math.sub currentDepth 1) "../"))
+                  Logic.and (Logic.not (Lists.null currentSegs)) (Equality.equal (Optionals.withDefault "" (Lists.head currentSegs)) "test")
+          baseUpPrefix =
+                  Logic.ifElse (Equality.equal currentDepth 1) "./" (Strings.concat (Lists.replicate (Math.sub currentDepth 1) "../"))
           lines =
                   Lists.map (\entry ->
                     let ns = Pairs.first entry
                         locals = Pairs.second entry
                         targetSegs = Lists.drop 1 (Strings.splitOn "." (Packaging.unModuleName ns))
                         targetIsTest =
-                                Logic.and (Logic.not (Lists.null targetSegs)) (Equality.equal (Optionals.fromOptional "" (Lists.maybeHead targetSegs)) "test")
+                                Logic.and (Logic.not (Lists.null targetSegs)) (Equality.equal (Optionals.withDefault "" (Lists.head targetSegs)) "test")
                         targetPathSegs =
-                                Logic.ifElse (Logic.and (Equality.equal (Optionals.fromOptional "" (Lists.maybeHead targetSegs)) "lib") (Logic.not (Equality.equal (Packaging.unModuleName ns) "hydra.lib.defaults"))) (Lists.concat2 [
+                                Logic.ifElse (Equality.equal (Optionals.withDefault "" (Lists.head targetSegs)) "lib") (Lists.concat2 [
                                   "overlay",
                                   "typescript"] targetSegs) targetSegs
-                        targetPath = Strings.intercalate "/" targetPathSegs
+                        targetPath = Strings.join "/" targetPathSegs
                         upPrefix =
-                                Logic.ifElse (Logic.and currentIsTest (Logic.not targetIsTest)) (Strings.cat2 baseUpPrefix "../../../main/typescript/hydra/") baseUpPrefix
-                        nsSlug = Strings.intercalate "_" targetSegs
-                        moduleAlias = Logic.ifElse (Equality.equal kind "type") (Strings.cat2 "$type_" nsSlug) (Strings.cat2 "$mod_" nsSlug)
-                    in (Strings.cat [
+                                Logic.ifElse (Logic.and currentIsTest (Logic.not targetIsTest)) (Strings.concat2 baseUpPrefix "../../../main/typescript/hydra/") baseUpPrefix
+                        nsSlug = Strings.join "_" targetSegs
+                        moduleAlias = Logic.ifElse (Equality.equal kind "type") (Strings.concat2 "$type_" nsSlug) (Strings.concat2 "$mod_" nsSlug)
+                    in (Strings.concat [
                       importKeyword,
                       " * as ",
                       moduleAlias,
@@ -711,7 +712,7 @@
                       upPrefix,
                       targetPath,
                       ".js\";\n"])) (Maps.toList grouped)
-      in (Strings.cat lines)
+      in (Strings.concat lines)
 
 -- | Look up a primitive by name and return its per-parameter laziness flags in parameter order
 lazyFlagsForPrimitive :: Graph.Graph -> Core.Name -> [Bool]
@@ -761,25 +762,25 @@
                   Lists.foldl (\acc -> \td -> Sets.union acc (collectTermImports currentNs (Packaging.termDefinitionBody td))) Sets.empty termDefs
           typeImportsBlock = importsToText "type" currentNs typeImports
           termImportsBlock = importsToText "value" currentNs termImports
-          importsBlock = Strings.cat2 typeImportsBlock termImportsBlock
+          importsBlock = Strings.concat2 typeImportsBlock termImportsBlock
       in (Eithers.bind (Eithers.mapList (encodeTypeDefinition cx g currentNs) typeDefs) (\typeItems ->
         let termItems = Lists.map (encodeTermDefinition cx g currentNs) termDefs
             allItems = Lists.concat2 typeItems termItems
             mModuleDoc = Optionals.bind (Packaging.moduleMetadata mod) (\em -> Packaging.entityMetadataDescription em)
-            moduleDocText = Optionals.cases mModuleDoc "" (\d -> Strings.cat2 (Serde.toTypeScriptComments d []) "\n\n")
-            header = Strings.cat2 "// Note: this is an automatically generated file. Do not edit.\n\n" moduleDocText
+            moduleDocText = Optionals.cases mModuleDoc "" (\d -> Strings.concat2 (Serde.toTypeScriptComments d []) "\n\n")
+            header = Strings.concat2 "// Note: this is an automatically generated file. Do not edit.\n\n" moduleDocText
             renderItem =
                     \docAndItem ->
                       let mdoc = Pairs.first docAndItem
                           item = Pairs.second docAndItem
                           itemText = printModuleItem item
-                      in (Optionals.cases mdoc itemText (\d -> Strings.cat [
+                      in (Optionals.cases mdoc itemText (\d -> Strings.concat [
                         Serde.toTypeScriptComments d [],
                         "\n",
                         itemText]))
-            body = Strings.intercalate "\n\n" (Lists.map renderItem allItems)
+            body = Strings.join "\n\n" (Lists.map renderItem allItems)
             filePath = Names.moduleNameToFilePath Util.CaseConventionCamel (File.FileExtension "ts") (Packaging.moduleName mod)
-        in (Right (Maps.singleton filePath (Strings.cat [
+        in (Right (Maps.singleton filePath (Strings.concat [
           header,
           importsBlock,
           (Logic.ifElse (Equality.equal importsBlock "") "" "\n"),
@@ -794,15 +795,15 @@
           params = printTypeParameterList (Syntax.interfaceDeclarationTypeParameters decl)
           exts = Syntax.interfaceDeclarationExtends decl
           extClause =
-                  Logic.ifElse (Lists.null exts) "" (Strings.cat2 " extends " (Strings.intercalate ", " (Lists.map printTypeExpression exts)))
+                  Logic.ifElse (Lists.null exts) "" (Strings.concat2 " extends " (Strings.join ", " (Lists.map printTypeExpression exts)))
           members = Syntax.interfaceDeclarationMembers decl
-          renderMember = \ps -> Strings.intercalate "\n  " (Strings.lines (printPropertySignature ps))
+          renderMember = \ps -> Strings.join "\n  " (Strings.lines (printPropertySignature ps))
           body =
-                  Logic.ifElse (Lists.null members) "" (Strings.cat [
+                  Logic.ifElse (Lists.null members) "" (Strings.concat [
                     "\n  ",
-                    (Strings.intercalate ";\n  " (Lists.map renderMember members)),
+                    (Strings.join ";\n  " (Lists.map renderMember members)),
                     ";\n"])
-      in (Strings.cat [
+      in (Strings.concat [
         "export interface ",
         name,
         params,
@@ -838,13 +839,13 @@
 
       let mcomments = Syntax.propertySignatureComments ps
           line =
-                  Strings.cat [
+                  Strings.concat [
                     Logic.ifElse (Syntax.propertySignatureReadonly ps) "readonly " "",
                     (Syntax.unIdentifier (Syntax.propertySignatureName ps)),
                     (Logic.ifElse (Syntax.propertySignatureOptional ps) "?" ""),
                     ": ",
                     (printTypeExpression (Syntax.propertySignatureType ps))]
-      in (Optionals.cases mcomments line (\dc -> Strings.cat [
+      in (Optionals.cases mcomments line (\dc -> Strings.concat [
         Serde.toTypeScriptComments (Syntax.documentationCommentDescription dc) (Syntax.documentationCommentTags dc),
         "\n",
         line]))
@@ -856,7 +857,7 @@
       let name = Syntax.unIdentifier (Syntax.typeAliasDeclarationName decl)
           params = printTypeParameterList (Syntax.typeAliasDeclarationTypeParameters decl)
           rhs = printTypeExpression (Syntax.typeAliasDeclarationType decl)
-      in (Strings.cat [
+      in (Strings.concat [
         "export type ",
         name,
         params,
@@ -870,28 +871,28 @@
     case t of
       Syntax.TypeExpressionIdentifier v0 -> Syntax.unIdentifier v0
       Syntax.TypeExpressionLiteral v0 -> printLiteral v0
-      Syntax.TypeExpressionArray v0 -> Strings.cat [
+      Syntax.TypeExpressionArray v0 -> Strings.concat [
         "ReadonlyArray<",
         (printTypeExpression (Syntax.unArrayTypeExpression v0)),
         ">"]
-      Syntax.TypeExpressionTuple v0 -> Strings.cat [
+      Syntax.TypeExpressionTuple v0 -> Strings.concat [
         "readonly [",
-        (Strings.intercalate ", " (Lists.map printTypeExpression v0)),
+        (Strings.join ", " (Lists.map printTypeExpression v0)),
         "]"]
-      Syntax.TypeExpressionUnion v0 -> Strings.intercalate " | " (Lists.map printTypeExpression v0)
-      Syntax.TypeExpressionIntersection v0 -> Strings.intercalate " & " (Lists.map printTypeExpression v0)
-      Syntax.TypeExpressionParameterized v0 -> Strings.cat [
+      Syntax.TypeExpressionUnion v0 -> Strings.join " | " (Lists.map printTypeExpression v0)
+      Syntax.TypeExpressionIntersection v0 -> Strings.join " & " (Lists.map printTypeExpression v0)
+      Syntax.TypeExpressionParameterized v0 -> Strings.concat [
         printTypeExpression (Syntax.parameterizedTypeExpressionBase v0),
         "<",
-        (Strings.intercalate ", " (Lists.map printTypeExpression (Syntax.parameterizedTypeExpressionArguments v0))),
+        (Strings.join ", " (Lists.map printTypeExpression (Syntax.parameterizedTypeExpressionArguments v0))),
         ">"]
-      Syntax.TypeExpressionOptional v0 -> Strings.cat [
+      Syntax.TypeExpressionOptional v0 -> Strings.concat [
         printTypeExpression v0,
         " | undefined"]
-      Syntax.TypeExpressionReadonly v0 -> Strings.cat2 "readonly " (printTypeExpression v0)
-      Syntax.TypeExpressionObject v0 -> Strings.cat [
+      Syntax.TypeExpressionReadonly v0 -> Strings.concat2 "readonly " (printTypeExpression v0)
+      Syntax.TypeExpressionObject v0 -> Strings.concat [
         "{ ",
-        (Strings.intercalate "; " (Lists.map printPropertySignature v0)),
+        (Strings.join "; " (Lists.map printPropertySignature v0)),
         " }"]
       Syntax.TypeExpressionFunction _ -> "((...args: any[]) => any)"
       Syntax.TypeExpressionAny -> "any"
@@ -906,7 +907,7 @@
 
       let name = Syntax.unIdentifier (Syntax.typeParameterName tp)
           constraint = Syntax.typeParameterConstraint tp
-      in (Optionals.cases constraint name (\c -> Strings.cat [
+      in (Optionals.cases constraint name (\c -> Strings.concat [
         name,
         " extends ",
         (printTypeExpression c)]))
@@ -914,9 +915,9 @@
 -- | Render a generic parameter list, or the empty string when there are no parameters
 printTypeParameterList :: [Syntax.TypeParameter] -> String
 printTypeParameterList tps =
-    Logic.ifElse (Lists.null tps) "" (Strings.cat [
+    Logic.ifElse (Lists.null tps) "" (Strings.concat [
       "<",
-      (Strings.intercalate ", " (Lists.map printTypeParameter tps)),
+      (Strings.join ", " (Lists.map printTypeParameter tps)),
       ">"])
 
 -- | Sanitize a Hydra parameter name into a valid, non-reserved TS identifier
@@ -936,7 +937,7 @@
                         deps = Lists.filter (\n -> Maps.member n byName) (Sets.toList freeVars)
                     in (bname, deps)) bindings
           sccs = Sorting.topologicalSortComponents adjacency
-      in (Optionals.cat (Lists.map (\n -> Maps.lookup n byName) (Lists.concat sccs)))
+      in (Optionals.givens (Lists.map (\n -> Maps.lookup n byName) (Lists.concat sccs)))
 
 -- | Reorder term definitions so each appears after the intra-module definitions it depends on
 sortTermDefsTopologically :: t0 -> [Packaging.TermDefinition] -> [Packaging.TermDefinition]
@@ -951,7 +952,7 @@
                         deps = Lists.filter (\n -> Maps.member n byName) (Sets.toList freeVars)
                     in (tname, deps)) tdefs
           sccs = Sorting.topologicalSortComponents adjacency
-      in (Optionals.cat (Lists.map (\n -> Maps.lookup n byName) (Lists.concat sccs)))
+      in (Optionals.givens (Lists.map (\n -> Maps.lookup n byName) (Lists.concat sccs)))
 
 -- | Strip leading forall quantifiers from a type, returning the innermost body
 stripForalls :: Core.Type -> Core.Type
@@ -1048,14 +1049,14 @@
 tsDocEntityRef :: Packaging.EntityReference -> String
 tsDocEntityRef x =
     case x of
-      Packaging.EntityReferenceDefinition v0 -> Strings.cat2 "{@link " (Strings.cat2 (case v0 of
+      Packaging.EntityReferenceDefinition v0 -> Strings.concat2 "{@link " (Strings.concat2 (case v0 of
         Packaging.DefinitionReferencePrimitive v1 -> Names.localNameOf v1
         Packaging.DefinitionReferenceTerm v1 -> Names.localNameOf v1
         Packaging.DefinitionReferenceType v1 -> Names.localNameOf v1) "}")
       Packaging.EntityReferenceModule v0 -> Packaging.unModuleName v0
       Packaging.EntityReferencePackage v0 -> Packaging.unPackageName v0
-      Packaging.EntityReferenceTermExpr v0 -> Strings.cat2 "`" (Strings.cat2 v0 "`")
-      Packaging.EntityReferenceTypeExpr v0 -> Strings.cat2 "`" (Strings.cat2 v0 "`")
+      Packaging.EntityReferenceTermExpr v0 -> Strings.concat2 "`" (Strings.concat2 v0 "`")
+      Packaging.EntityReferenceTypeExpr v0 -> Strings.concat2 "`" (Strings.concat2 v0 "`")
 
 -- | Identity getter for analyzeFunctionTerm when the environment is a Graph
 tsEnvGetGraph :: t0 -> t0
@@ -1071,9 +1072,9 @@
 
       let escapeChar =
               \c -> Logic.ifElse (Equality.equal c 34) "\\\"" (Logic.ifElse (Equality.equal c 92) "\\\\" (Logic.ifElse (Equality.equal c 10) "\\n" (Logic.ifElse (Equality.equal c 13) "\\r" (Logic.ifElse (Equality.equal c 9) "\\t" (Logic.ifElse (Equality.equal c 8) "\\b" (Logic.ifElse (Equality.equal c 12) "\\f" (Strings.fromList (Lists.pure c))))))))
-      in (Strings.cat [
+      in (Strings.concat [
         "\"",
-        (Strings.cat (Lists.map escapeChar (Strings.toList s))),
+        (Strings.concat (Lists.map escapeChar (Strings.toList s))),
         "\""])
 
 -- | A bare identifier expression
diff --git a/src/main/haskell/Hydra/TypeScript/Serde.hs b/src/main/haskell/Hydra/TypeScript/Serde.hs
--- a/src/main/haskell/Hydra/TypeScript/Serde.hs
+++ b/src/main/haskell/Hydra/TypeScript/Serde.hs
@@ -24,6 +24,7 @@
 import qualified Hydra.Overlay.Haskell.Lib.Logic as Logic
 import qualified Hydra.Overlay.Haskell.Lib.Math as Math
 import qualified Hydra.Overlay.Haskell.Lib.Optionals as Optionals
+import qualified Hydra.Overlay.Haskell.Lib.Ordering as Ordering
 import qualified Hydra.Overlay.Haskell.Lib.Pairs as Pairs
 import qualified Hydra.Overlay.Haskell.Lib.Strings as Strings
 import qualified Hydra.Packaging as Packaging
@@ -51,7 +52,7 @@
 -- | True iff every codepoint is an ASCII digit 0-9, and the list is non-empty
 allDigits :: [Int] -> Bool
 allDigits cps =
-    Logic.and (Equality.gt (Lists.length cps) 0) (Lists.foldl (\acc -> \c -> Logic.and acc (Logic.and (Equality.gte c 48) (Equality.lte c 57))) True cps)
+    Logic.and (Ordering.gt (Lists.length cps) 0) (Lists.foldl (\acc -> \c -> Logic.and acc (Logic.and (Ordering.gte c 48) (Ordering.lte c 57))) True cps)
 
 -- | Convert an array element to an AST expression
 arrayElementToExpr :: Syntax.ArrayElement -> Ast.Expr
@@ -315,25 +316,25 @@
           mparamName = Syntax.documentationTagParamName tag
           description = Syntax.documentationTagDescription tag
           typePart =
-                  Optionals.cases mtype "" (\t -> Strings.cat [
+                  Optionals.cases mtype "" (\t -> Strings.concat [
                     "{",
                     (typeExpressionToString t),
                     "}"])
           paramPart = Optionals.cases mparamName "" (\p -> Syntax.unIdentifier p)
           parts =
                   [
-                    Strings.cat2 "@" name,
+                    Strings.concat2 "@" name,
                     typePart,
                     paramPart,
                     description]
           nonEmpty = Lists.filter (\p -> Logic.not (Equality.equal p "")) parts
-      in (Strings.cat2 " * " (Strings.intercalate " " nonEmpty))
+      in (Strings.concat2 " * " (Strings.join " " nonEmpty))
 
 -- | Escape special characters in a string for TypeScript
 escapeString :: String -> Bool -> String
 escapeString s singleQuote =
 
-      let replace = \old -> \new_ -> \str -> Strings.intercalate new_ (Strings.splitOn old str)
+      let replace = \old -> \new_ -> \str -> Strings.join new_ (Strings.splitOn old str)
           s1 = replace "\\" "\\\\" s
           s2 = replace "\n" "\\n" s1
           s3 = replace "\r" "\\r" s2
@@ -602,9 +603,9 @@
 
       let cps = Strings.toList s
           len = Lists.length cps
-          first = Optionals.fromOptional 0 (Lists.maybeHead cps)
-          rest = Logic.ifElse (Equality.gt len 0) (Lists.drop 1 cps) []
-      in (Logic.and (Equality.gt len 1) (Logic.and (Equality.equal first 84) (allDigits rest)))
+          first = Optionals.withDefault 0 (Lists.head cps)
+          rest = Logic.ifElse (Ordering.gt len 0) (Lists.drop 1 cps) []
+      in (Logic.and (Ordering.gt len 1) (Logic.and (Equality.equal first 84) (allDigits rest)))
 
 -- | Convert a labeled statement to an AST expression
 labeledStatementToExpr :: Syntax.LabeledStatement -> Ast.Expr
@@ -625,7 +626,7 @@
       Syntax.LiteralBoolean v0 -> Serialization.cst (Logic.ifElse v0 "true" "false")
       Syntax.LiteralNull -> Serialization.cst "null"
       Syntax.LiteralUndefined -> Serialization.cst "undefined"
-      Syntax.LiteralBigInt v0 -> Serialization.cst (Strings.cat2 (Literals.showBigint v0) "n")
+      Syntax.LiteralBigInt v0 -> Serialization.cst (Strings.concat2 (Literals.showBigint v0) "n")
       Syntax.LiteralTemplate v0 -> templateLiteralToExpr v0
 
 -- | Convert a member expression to an AST expression
@@ -763,8 +764,8 @@
 patternToString pat =
     case pat of
       Syntax.PatternIdentifier v0 -> Syntax.unIdentifier v0
-      Syntax.PatternRest v0 -> Strings.cat2 "..." (patternToString (Syntax.unRestElement v0))
-      Syntax.PatternTyped v0 -> Strings.cat [
+      Syntax.PatternRest v0 -> Strings.concat2 "..." (patternToString (Syntax.unRestElement v0))
+      Syntax.PatternTyped v0 -> Strings.concat [
         patternToString (Syntax.typedPatternPattern v0),
         ": ",
         (tsTypeExpressionToString (Syntax.typedPatternType v0))]
@@ -834,7 +835,7 @@
           singleQuote = Syntax.stringLiteralSingleQuote s
           quote = Logic.ifElse singleQuote "'" "\""
           escaped = escapeString value singleQuote
-      in (Serialization.cst (Strings.cat [
+      in (Serialization.cst (Strings.concat [
         quote,
         escaped,
         quote]))
@@ -869,9 +870,9 @@
 
       let quasis = Syntax.templateLiteralQuasis t
           exprs = Syntax.templateLiteralExpressions t
-      in (Serialization.cst (Strings.cat [
+      in (Serialization.cst (Strings.concat [
         "`",
-        (Strings.intercalate "" (Lists.map (\q -> Syntax.templateElementValue q) quasis)),
+        (Strings.join "" (Lists.map (\q -> Syntax.templateElementValue q) quasis)),
         "`"]))
 
 -- | Convert a throw statement to an AST expression
@@ -884,20 +885,20 @@
 -- | Convert a string to a TypeScript line comment. Empty source lines emit `//` (no trailing space).
 toLineComment :: String -> String
 toLineComment s =
-    Strings.intercalate "\n" (Lists.map (\line -> Logic.ifElse (Equality.equal line "") "//" (Strings.cat2 "// " line)) (Strings.lines s))
+    Strings.join "\n" (Lists.map (\line -> Logic.ifElse (Equality.equal line "") "//" (Strings.concat2 "// " line)) (Strings.lines s))
 
 -- | Format a description and tags as a JSDoc comment. Empty doc lines emit ` *` (no trailing space) so blank lines don't carry trailing whitespace.
 toTypeScriptComments :: String -> [Syntax.DocumentationTag] -> String
 toTypeScriptComments desc tags =
 
       let descLines =
-              Logic.ifElse (Equality.equal desc "") [] (Lists.map (\line -> Logic.ifElse (Equality.equal line "") " *" (Strings.cat2 " * " line)) (Strings.lines desc))
+              Logic.ifElse (Equality.equal desc "") [] (Lists.map (\line -> Logic.ifElse (Equality.equal line "") " *" (Strings.concat2 " * " line)) (Strings.lines desc))
           tagLines = Lists.map documentationTagToLine tags
           allLines =
                   Lists.concat [
                     descLines,
                     tagLines]
-      in (Logic.ifElse (Lists.null allLines) "" (Strings.intercalate "\n" (Lists.concat [
+      in (Logic.ifElse (Lists.null allLines) "" (Strings.join "\n" (Lists.concat [
         [
           "/**"],
         allLines,
@@ -938,25 +939,25 @@
       Syntax.TypeExpressionAny -> "any"
       Syntax.TypeExpressionVoid -> "void"
       Syntax.TypeExpressionNever -> "never"
-      Syntax.TypeExpressionArray v0 -> Strings.cat [
+      Syntax.TypeExpressionArray v0 -> Strings.concat [
         "ReadonlyArray<",
         (tsTypeExpressionToString (Syntax.unArrayTypeExpression v0)),
         ">"]
-      Syntax.TypeExpressionTuple v0 -> Strings.cat [
+      Syntax.TypeExpressionTuple v0 -> Strings.concat [
         "readonly [",
-        (Strings.intercalate ", " (Lists.map tsTypeExpressionToString v0)),
+        (Strings.join ", " (Lists.map tsTypeExpressionToString v0)),
         "]"]
-      Syntax.TypeExpressionUnion v0 -> Strings.intercalate " | " (Lists.map tsTypeExpressionToString v0)
-      Syntax.TypeExpressionIntersection v0 -> Strings.intercalate " & " (Lists.map tsTypeExpressionToString v0)
-      Syntax.TypeExpressionParameterized v0 -> Strings.cat [
+      Syntax.TypeExpressionUnion v0 -> Strings.join " | " (Lists.map tsTypeExpressionToString v0)
+      Syntax.TypeExpressionIntersection v0 -> Strings.join " & " (Lists.map tsTypeExpressionToString v0)
+      Syntax.TypeExpressionParameterized v0 -> Strings.concat [
         tsTypeExpressionToString (Syntax.parameterizedTypeExpressionBase v0),
         "<",
-        (Strings.intercalate ", " (Lists.map tsTypeExpressionToString (Syntax.parameterizedTypeExpressionArguments v0))),
+        (Strings.join ", " (Lists.map tsTypeExpressionToString (Syntax.parameterizedTypeExpressionArguments v0))),
         ">"]
-      Syntax.TypeExpressionOptional v0 -> Strings.cat [
+      Syntax.TypeExpressionOptional v0 -> Strings.concat [
         tsTypeExpressionToString v0,
         " | undefined"]
-      Syntax.TypeExpressionReadonly v0 -> Strings.cat2 "readonly " (tsTypeExpressionToString v0)
+      Syntax.TypeExpressionReadonly v0 -> Strings.concat2 "readonly " (tsTypeExpressionToString v0)
       Syntax.TypeExpressionUnknown -> "unknown"
       Syntax.TypeExpressionFunction _ -> "((...args: any[]) => any)"
       _ -> "unknown"
@@ -970,7 +971,7 @@
       Syntax.TypeExpressionVoid -> "void"
       Syntax.TypeExpressionNever -> "never"
       Syntax.TypeExpressionLiteral _ -> "literal"
-      Syntax.TypeExpressionArray v0 -> Strings.cat2 (typeExpressionToString (Syntax.unArrayTypeExpression v0)) "[]"
+      Syntax.TypeExpressionArray v0 -> Strings.concat2 (typeExpressionToString (Syntax.unArrayTypeExpression v0)) "[]"
       Syntax.TypeExpressionFunction v0 ->
         let params = Syntax.functionTypeExpressionParameters v0
             rt = Syntax.functionTypeExpressionReturnType v0
@@ -979,28 +980,28 @@
                       let i = Pairs.first acc
                           soFar = Pairs.second acc
                           this =
-                                  Strings.cat [
+                                  Strings.concat [
                                     "_a",
                                     (Literals.showInt32 i),
                                     ": ",
                                     (typeExpressionToString p)]
                       in (Math.add i 1, (Lists.concat2 soFar (Lists.pure this)))) (0, []) params)
-        in (Strings.cat [
+        in (Strings.concat [
           "(",
-          (Strings.intercalate ", " rendered),
+          (Strings.join ", " rendered),
           ") => ",
           (typeExpressionToString rt)])
       Syntax.TypeExpressionObject _ -> "Object"
-      Syntax.TypeExpressionUnion v0 -> Strings.intercalate "|" (Lists.map typeExpressionToString v0)
+      Syntax.TypeExpressionUnion v0 -> Strings.join "|" (Lists.map typeExpressionToString v0)
       Syntax.TypeExpressionParameterized v0 ->
         let base = Syntax.parameterizedTypeExpressionBase v0
             args = Syntax.parameterizedTypeExpressionArguments v0
-        in (Strings.cat [
+        in (Strings.concat [
           typeExpressionToString base,
           "<",
-          (Strings.intercalate ", " (Lists.map typeExpressionToString args)),
+          (Strings.join ", " (Lists.map typeExpressionToString args)),
           ">"])
-      Syntax.TypeExpressionOptional v0 -> Strings.cat2 "?" (typeExpressionToString v0)
+      Syntax.TypeExpressionOptional v0 -> Strings.concat2 "?" (typeExpressionToString v0)
 
 -- | Render `<pattern>: <type>` (TypeScript parameter / variable type annotation)
 typedPatternToExpr :: Syntax.TypedPattern -> Ast.Expr
@@ -1010,7 +1011,7 @@
           typ = Syntax.typedPatternType tp
           innerStr = patternToString innerPat
           typeStr = tsTypeExpressionToString typ
-      in (Serialization.cst (Strings.cat [
+      in (Serialization.cst (Strings.concat [
         innerStr,
         ": ",
         typeStr]))
