packages feed

hydra-python 0.17.5 → 0.17.6

raw patch · 15 files changed

+224/−49 lines, 15 filesdep ~hydra-kernelPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: hydra-kernel

API changes (from Hackage documentation)

Files

CHANGELOG.md view
@@ -15,6 +15,168 @@  --- +## [0.17.6] - 2026-08-30++Point release on the 0.17.x line, and the last backward-incompatible batch before the 1.0 surface+freeze. Five kernel-surface changes land together as the "0.17 breaking batch":+`null` becomes `isEmpty`, `read*`/`show*` become `parse*`/`print*`, `TypeScheme.constraints` and+`TypeVariableConstraints.classes` change shape, and the constructor primitives are finalized.+Alongside them, a genuine soundness gap in type inference is fixed — class constraints now propagate+through function-domain positions — and the cold-seed path is rebuilt on the Java host so that+breaking core-type changes are no longer structurally impossible to bootstrap.++**Backward-incompatible.** All five surface changes below alter the published kernel. Code written+against 0.17.5 must be updated:++- **[#682]** `hydra.lib.{lists,sets,maps,strings}.null` -> `.isEmpty`.+- **[#691]** the `read*`/`show*` family -> `parse*`/`print*`.+- **[#683]** `TypeScheme.constraints`: `optional<map>` -> plain `map`.+- **[#685]** `TypeVariableConstraints.classes`: `list` -> `set`.+- **[#687]** constructor primitives finalized: `lists.pure` is removed; `optionals.given`,+  `eithers.left`/`right` and `pairs.pair` are added.++[#682]: https://github.com/CategoricalData/hydra/issues/682+[#683]: https://github.com/CategoricalData/hydra/issues/683+[#685]: https://github.com/CategoricalData/hydra/issues/685+[#687]: https://github.com/CategoricalData/hydra/issues/687+[#691]: https://github.com/CategoricalData/hydra/issues/691++### Highlights++- **Class constraints propagate through contravariant positions**+  ([#702](https://github.com/CategoricalData/hydra/issues/702)): inference silently dropped a class+  constraint when the constrained type variable was bound through the **domain** (input) position of a+  higher-order function argument, while transferring it correctly in output positions — a real soundness+  gap in the type checker. It had been papered over twice by freezing `encodeMap`/`encodeSet` to+  monomorphic `Int`. Both freezes and the [#554](https://github.com/CategoricalData/hydra/issues/554)+  `toPrimitive` stopgap are now removed, the definitions re-polymorphized, and a domain-position+  regression test added. A `sets.filter` overlay lands across Java, Python, Scala, TypeScript and the+  Lisp dialects as its first consumer.+- **Cold-seed rebuilt on the Java host**+  ([#703](https://github.com/CategoricalData/hydra/issues/703)): CI's cold-seed steps compiled HEAD's+  kernel `Types` source against the *published* Hackage `hydra-kernel`, which is sound only for additive+  changes and structurally impossible for any breaking core-type-shape change — the root of a recurring+  red-CI class (#500, #608, #617, #417, #683). The Haskell cold-seeder (`ColdSeedMain`, `typesmods/`,+  Check-2) is deleted and replaced by a data-driven Java-host schema-walking seed+  (`seed-dist-haskell.sh`), which decodes `dist/json` and emits Haskell text without ever linking+  HEAD types against a published kernel.+- **`hydra.paths` completed** ([#716](https://github.com/CategoricalData/hydra/issues/716)):+  the step unions are realigned with the `hydra.core` term and type grammars — missing variants+  added (`annotatedAnnotation`, `eitherLeft`/`eitherRight`, `effect`), undirected steps given a+  direction, and variants named after retired constructors renamed. `hydra.print.paths` is rewritten+  as serialization-only (printers, parsers and a round-trip law), and the graph view moves to a new+  `hydra.shredding` module (`shredGraph`/`shredTerm`/`shredSchema`), which the Graphviz coder now+  consumes.+- **`hydra.lib.ordering` is genuinely structural on every host**+  ([#718](https://github.com/CategoricalData/hydra/issues/718)): the Java, Python and Scala overlay+  implementations fell back to comparing *printed strings* for non-literal and mixed-variant terms,+  contradicting the normative `ordering-and-equality.md` (records field-by-field in declaration+  order, unions by declared-variant order then payload, wrappers by wrapped value, decimals by+  numeric value then scale — with no print-based fallback anywhere). All three are now structural;+  Java delegates to the generated `compareTo`.+- **Bash driver-layer audit** ([#714](https://github.com/CategoricalData/hydra/issues/714)):+  a prerequisite to the remaining #416 promotion. Six dead build scripts superseded by+  `transform-json-to-target.sh` are deleted, and the #608 oil-and-water and #540 header-idempotency+  regression harnesses are wired into `test-regressions.sh`.++- **Backward-compatibility and deprecation policy**+  ([#676](https://github.com/CategoricalData/hydra/issues/676)): adds the normative spec chapter defining+  what "compatible" means after 1.0 — the additivity calculus, the deprecation/rename mechanism, and+  enforcement. `LifecycleInfo.deprecatedSince` moves from defined-but-unused to populated on **32**+  kernel primitives slated for 0.18 deprecation, via a new `deprecatedSince` DSL helper.+- **Effect-sequencing contract specified and tested**+  ([#675](https://github.com/CategoricalData/hydra/issues/675)): `hydra.lib.effects` carries a sequencing+  contract — effects composed in a specified order, exactly once each, with `bind`'s continuation deferred+  until the prior effect has run. On the lazy Haskell host this falls out of the evaluation model; on the+  eight eager hosts it depended entirely on each hand-written interpreter. The obligations are now written+  into `effects.md` and backed by ordering-observation tests for `bind`/`foldList`/`mapList`/`mapOptional`.+- **Non-GC memory-discipline investigation**+  ([#678](https://github.com/CategoricalData/hydra/issues/678)): Hydra's data model says nothing about+  allocation, freeing, or ownership, which is what gates Swift, Rust, C++ and C as runtime hosts. This+  investigation delivers per-language verdicts plus leak-free proof-of-concept implementations — Rust+  (`Box` structural ownership), C++ (`unique_ptr` + arena) and C (arena), all ASan/LSan-clean on+  construct-and-drop of a recursive `Term` — and an airtight analysis of Swift's class-forcing requirement.+- **Build system promotion continues** ([#416](https://github.com/CategoricalData/hydra/issues/416)):+  adds `hydra.build.Registry`, which models per-language build identity as data (name / coder package /+  family) with per-script scope lists. `syncMatrix` and `langExpansion` are rewired onto it, and the+  hardcoded language lists in the test and bench scripts are retired in favour of a generated+  `languages.json`. Later in the cycle: `publishsets.reverseDepClosure` and+  `publishsets.requiresCoders` promote reverse-dependency propagation and per-package coder-loading+  into data, an `expected-libraries.json` artifact lets the Common Lisp and Emacs Lisp harnesses+  fail fast on a missing `hydra.lib`, and a host-independent `apply-assembly-plan.sh` executor+  (with a conformance test) takes over the Java `assemble-distribution` Step 0.+- **Serialization specification chapter**+  ([#674](https://github.com/CategoricalData/hydra/issues/674)): documents serializability, the+  encode/decode contract, and the round-trip law; `isSerializable` now forbids `void`+  ([#690](https://github.com/CategoricalData/hydra/issues/690)), and `hydra.lib.functions.absurd` is added+  as the void eliminator ([#684](https://github.com/CategoricalData/hydra/issues/684)).++### Bug fixes++- **Hoisting silently produced terms with free variables**+  ([#717](https://github.com/CategoricalData/hydra/issues/717)):+  `augmentBindingsWithNewFreeVars` returned a binding *unchanged* when a captured variable had no+  type in the context, yielding a top-level binding with free variables — a term valid before+  hoisting and invalid after, produced with no error. It is now total and fails loudly, per the+  kernel's fail-immediately rule.+- **TypeScript `div`/`mod` used truncating semantics**+  ([#677](https://github.com/CategoricalData/hydra/issues/677)): corrected to floor/Knuth division via+  shared bigint helpers, with an `Optional` codomain; the dead `maybeDiv`/`maybeMod` are deleted and an+  emitted-path test added.+- **Overlay lag behind the `null` -> `isEmpty` rename**+  ([#682](https://github.com/CategoricalData/hydra/issues/682)): the Java, Python, Scala, TypeScript and+  Lisp overlays each kept a stale spelling (`isEmpty_`, a half-renamed Python `null` impl, and Lisp+  camelCase where the coder emits snake_case), breaking generation until reconciled.+- **`check-haskell-def-completeness` could not resolve qualified assembly references**+  ([#683](https://github.com/CategoricalData/hydra/issues/683)), surfaced once the #703 cold-clone path+  began reaching the check.+- **Void-typed definitions leaked into DSL-ref generation**+  ([#684](https://github.com/CategoricalData/hydra/issues/684)): `absurd` and friends are now excluded+  across all hosts.+- **Scheme bootstrap loader gaps** ([#641](https://github.com/CategoricalData/hydra/issues/641)):+  missing `functions.scm`/`ordering.scm` in the native-lib load list, missing defaults in the def-module+  load list, and a guile-only import allowlist.+- **Bootstrap diff detail was swallowed** ([#671](https://github.com/CategoricalData/hydra/issues/671)):+  now persisted to `<run>/<path>.diff`, with `compare_output`'s return value no longer discarded.+  Separately, `compare_output` mis-derived the `src/main` vs `src/test` root per file+  ([#706](https://github.com/CategoricalData/hydra/issues/706)).+- **Nested duplicate output path** ([#664](https://github.com/CategoricalData/hydra/issues/664)) from+  `hydra-kernel` being hardcoded into `defaultOutput`.+- **Bootstrap codegen exceptions hid their stack traces**+  ([#707](https://github.com/CategoricalData/hydra/issues/707)) in `bootstrap.ts`.++### Release tooling++- `bin/check-release-env.sh` ([#704](https://github.com/CategoricalData/hydra/issues/704)) adds a+  publish-time toolchain preflight, after JDK- and twine-version problems cost real time at 0.17.5.+- The TypeScript head's node floor is lowered to `^18.0.0 || >=20.0.0`, the true vitest constraint+  ([#708](https://github.com/CategoricalData/hydra/issues/708)).+- Hydra does not create GitHub Releases; the detached `.asc` signature stays in `release-artifacts/`+  until [#441](https://github.com/CategoricalData/hydra/issues/441)+  ([#508](https://github.com/CategoricalData/hydra/issues/508)).++### Known issues++- The `hostOverrides` shim is pinned to `{java: local, python: local}` for the duration of the breaking+  batch, since the new kernel surface is by definition absent from published 0.17.5. It must be retired+  once 0.17.6 is visible in Maven Central and PyPI+  ([#508](https://github.com/CategoricalData/hydra/issues/508)).+- **`hydra-ext` does not ship to Maven Central for Java**, as in 0.17.4 and 0.17.5: the Java coder's+  visitor-pattern inner interface still collides with an enclosing type named `Visitor`+  ([#643](https://github.com/CategoricalData/hydra/issues/643)), so the package does not compile for+  that target. It publishes to Hackage and PyPI as usual.+- The breaking batch leaves three deliberate 0.18 tails, each separately tracked:+  `effects.pure` is retained provisionally pending a name decision+  ([#688](https://github.com/CategoricalData/hydra/issues/688)); the `printable` type class that would+  promote the print/parse convention into enforced dispatch awaits+  [#497](https://github.com/CategoricalData/hydra/issues/497); and the literal conversion lattice is+  gated on [#129](https://github.com/CategoricalData/hydra/issues/129) via+  [#689](https://github.com/CategoricalData/hydra/issues/689). Anticipated `TypeClassConstraint`+  variants remain open as [#686](https://github.com/CategoricalData/hydra/issues/686) — the `set`+  element type must stay orderable as variants are added.++---+ ## [0.17.5] - 2026-08-19  Point release on the 0.17.x line. Two language-surface changes lead: sum-type eliminators unify on
hydra-python.cabal view
@@ -1,11 +1,11 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.38.1.+-- This file has been generated from package.yaml by hpack version 0.39.1. -- -- see: https://github.com/sol/hpack  name:           hydra-python-version:        0.17.5+version:        0.17.6 synopsis:       Hydra's Python coder: emit Python 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". Python support for Hydra category:       Data@@ -47,6 +47,6 @@   build-depends:       base >=4.19.0 && <4.22     , containers >=0.6.7 && <0.8-    , hydra-kernel ==0.17.5+    , hydra-kernel ==0.17.6     , scientific >=0.3.7 && <0.4   default-language: Haskell2010
src/main/haskell/Hydra/Dsl/Python/Environment.hs view
@@ -15,6 +15,7 @@ import qualified Hydra.Util as Util import Prelude hiding  (Enum, Ordering, decodeFloat, encodeFloat, fail, lines, map, pure, sum, unlines) import qualified Data.Scientific as Sci+import Data.Void import qualified Data.Map as M import qualified Data.Set as S 
src/main/haskell/Hydra/Dsl/Python/Names.hs view
@@ -38,6 +38,7 @@ import qualified Hydra.Variants as Variants import Prelude hiding  (Enum, Ordering, decodeFloat, encodeFloat, fail, lines, map, pure, sum, unlines) import qualified Data.Scientific as Sci+import Data.Void import qualified Data.Map as M import qualified Data.Set as S 
src/main/haskell/Hydra/Dsl/Python/Syntax.hs view
@@ -9,6 +9,7 @@ import qualified Hydra.Typed as Typed import Prelude hiding  (Enum, Ordering, decodeFloat, encodeFloat, fail, lines, map, pure, sum, unlines) import qualified Data.Scientific as Sci+import Data.Void  -- | DSL name token for hydra.python.syntax.AnnotatedRhs annotatedRhsAnnotatedRhs :: Typed.TypedName Syntax.AnnotatedRhs
src/main/haskell/Hydra/Dsl/Python/Utils.hs view
@@ -39,6 +39,7 @@ import qualified Hydra.Variants as Variants import Prelude hiding  (Enum, Ordering, decodeFloat, encodeFloat, fail, lines, map, pure, sum, unlines) import qualified Data.Scientific as Sci+import Data.Void import qualified Data.Set as S  -- | DSL reference to hydra.python.utils.annotatedExpression
src/main/haskell/Hydra/Python/Coder.hs view
@@ -67,6 +67,7 @@ import qualified Hydra.Variants as Variants import Prelude hiding  (Enum, Ordering, decodeFloat, encodeFloat, fail, lines, map, pure, sum, unlines) import qualified Data.Scientific as Sci+import Data.Void import qualified Data.Map as M import qualified Data.Set as S @@ -201,7 +202,7 @@                         body = Core.lambdaBody v0                     in (Optionals.match (Maps.lookup v countByName) (Maps.insert v 1 countByName, (Lists.cons field done)) (\count ->                       let count2 = Math.add count 1-                          v2 = Core.Name (Strings.concat2 (Core.unName v) (Literals.showInt32 count2))+                          v2 = Core.Name (Strings.concat2 (Core.unName v) (Literals.printInt32 count2))                           newBody = Reduction.alphaConvert v v2 body                           newLam =                                   Core.Lambda {@@ -343,7 +344,7 @@        let firstArg = Optionals.withDefault (Utils.pyNameToPyExpression (Syntax.Name "")) (Lists.head hargs)           restArgs = Lists.drop 1 hargs-          withRest = \e -> Logic.ifElse (Lists.null restArgs) e (Utils.functionCall (Utils.pyExpressionToPyPrimary e) restArgs)+          withRest = \e -> Logic.ifElse (Lists.isEmpty restArgs) e (Utils.functionCall (Utils.pyExpressionToPyPrimary e) restArgs)           defaultCase =                   Eithers.bind (encodeTermInline cx env False fun) (\pfun -> Right (Utils.functionCall (Utils.pyExpressionToPyPrimary pfun) hargs, rargs))       in case (Strip.deannotateAndDetypeTerm fun) of@@ -355,7 +356,7 @@         Core.TermUnwrap _ ->           let valueExpr = Utils.projectFromExpression firstArg (Syntax.Name "value")               allArgs = Lists.concat2 restArgs rargs-          in (Logic.ifElse (Lists.null allArgs) (Right (valueExpr, [])) (Right (Utils.functionCall (Utils.pyExpressionToPyPrimary valueExpr) allArgs, [])))+          in (Logic.ifElse (Lists.isEmpty allArgs) (Right (valueExpr, [])) (Right (Utils.functionCall (Utils.pyExpressionToPyPrimary valueExpr) allArgs, [])))         Core.TermLambda _ -> Eithers.bind (encodeTermInline cx env False fun) (\pfun -> Right (Utils.functionCall (Utils.pyExpressionToPyPrimary pfun) hargs, rargs))         Core.TermVariable v0 ->           let g = pythonEnvironmentGetGraph env@@ -366,7 +367,7 @@                 consumeCount = Ordering.min elArity (Lists.length allArgs)                 consumedArgs = Lists.take consumeCount allArgs                 remainingArgs = Lists.drop consumeCount allArgs-            in (Logic.ifElse (Lists.null consumedArgs) (Eithers.bind (encodeVariable cx env v0 []) (\expr -> Right (expr, rargs))) (Logic.ifElse (Sets.member v0 inlineVars) (Right (+            in (Logic.ifElse (Lists.isEmpty consumedArgs) (Eithers.bind (encodeVariable cx env v0 []) (\expr -> Right (expr, rargs))) (Logic.ifElse (Sets.member v0 inlineVars) (Right (               Utils.functionCall (Utils.pyExpressionToPyPrimary (lazyDotGet (PythonNames.termVariableReference env v0))) consumedArgs,               remainingArgs)) (Right (               Utils.functionCall (Utils.pyNameToPyPrimary (PythonNames.encodeName True Util.CaseConventionLowerSnake env v0)) consumedArgs,@@ -461,7 +462,7 @@                               Syntax.functionDefRawBlock = body}                 in (Right (Syntax.StatementCompound (Syntax.CompoundStatementFunction (Syntax.FunctionDefinition {                   Syntax.functionDefinitionDecorators = Nothing,-                  Syntax.functionDefinitionRaw = funcDefRaw})))))))))))) (\csa -> Logic.ifElse (Lists.null lambdaParams) (+                  Syntax.functionDefinitionRaw = funcDefRaw})))))))))))) (\csa -> Logic.ifElse (Lists.isEmpty lambdaParams) (           let mcs = extractCaseElimination term1           in (Optionals.match mcs (Eithers.bind (encodeTermMultiline cx env term1) (\stmts -> Optionals.match (Lists.head stmts) (Left (Errors.ErrorOther (Errors.OtherError "encodeTermMultiline returned no statements"))) (\x -> Right x))) (\cs ->             let tname = Core.caseStatementTypeName cs@@ -611,7 +612,7 @@                     Optionals.match (Packaging.termDefinitionSignature v0) (Core.TypeScheme {                       Core.typeSchemeVariables = [],                       Core.typeSchemeBody = (Core.TypeVariable (Core.Name "hydra.core.Unit")),-                      Core.typeSchemeConstraints = Nothing}) (\sig -> Scoping.termSignatureToTypeScheme sig)+                      Core.typeSchemeConstraints = Maps.empty}) (\sig -> Scoping.termSignatureToTypeScheme sig)         in (Eithers.bind (Annotations.getTermDescription cx (pythonEnvironmentGetGraph env) term) (\comment ->           let normComment = Optionals.map Formatting.normalizeComment comment           in (Eithers.bind (encodeTermAssignment cx env True name term typ normComment) (\stmt -> Right [@@ -675,13 +676,13 @@ encodeFloatValueEncodeFloat32 :: Float -> Either t0 Syntax.Expression encodeFloatValueEncodeFloat32 v = -      let s = Literals.showFloat32 v+      let s = Literals.printFloat32 v       in (Logic.ifElse (Equality.equal s "NaN") (Right (encodeFloatValuePySpecialFloat "nan")) (Logic.ifElse (Equality.equal s "Infinity") (Right (encodeFloatValuePySpecialFloat "inf")) (Logic.ifElse (Equality.equal s "-Infinity") (Right (encodeFloatValuePySpecialFloat "-inf")) (Right (Utils.pyAtomToPyExpression (Syntax.AtomNumber (Syntax.NumberFloat (Literals.float32ToFloat64 v))))))))  encodeFloatValueEncodeFloat64 :: Double -> Either t0 Syntax.Expression encodeFloatValueEncodeFloat64 v = -      let s = Literals.showFloat64 v+      let s = Literals.printFloat64 v       in (Logic.ifElse (Equality.equal s "NaN") (Right (encodeFloatValuePySpecialFloat "nan")) (Logic.ifElse (Equality.equal s "Infinity") (Right (encodeFloatValuePySpecialFloat "inf")) (Logic.ifElse (Equality.equal s "-Infinity") (Right (encodeFloatValuePySpecialFloat "-inf")) (Logic.ifElse (Equality.equal s "-0.0") (Right (encodeFloatValuePySpecialFloat "-0.0")) (Right (Utils.pyAtomToPyExpression (Syntax.AtomNumber (Syntax.NumberFloat v))))))))  encodeFloatValuePySpecialFloat :: String -> Syntax.Expression@@ -797,7 +798,7 @@           Utils.pyAtomToPyExpression (Syntax.AtomList (Utils.pyList (Lists.map (\byteVal -> Utils.pyAtomToPyExpression (Syntax.AtomNumber (Syntax.NumberInteger (Literals.int32ToBigint byteVal)))) byteValues)))]))       Core.LiteralBoolean v0 -> Right (Utils.pyAtomToPyExpression (Logic.ifElse v0 Syntax.AtomTrue Syntax.AtomFalse))       Core.LiteralDecimal v0 -> Right (Utils.functionCall (Utils.pyNameToPyPrimary (Syntax.Name "Decimal")) [-        Utils.singleQuotedString (Literals.showDecimal v0)])+        Utils.singleQuotedString (Literals.printDecimal v0)])       Core.LiteralFloat v0 -> encodeFloatValue v0       Core.LiteralInteger v0 -> encodeIntegerValue v0       Core.LiteralString v0 -> Right (Utils.stringToPyExpression Syntax.QuoteStyleDouble v0)@@ -872,7 +873,7 @@                     Logic.ifElse (Logic.or isTypeMod (Logic.not useInlineTypeParams)) (PythonEnvironment.pythonModuleMetadataTypeVariables meta) Sets.empty             tvarStmts = Lists.map (\tv -> tvarStatement (PythonNames.encodeTypeVariable tv)) (Sets.toList tvars)             body =-                    Lists.filter (\group -> Logic.not (Lists.null group)) (Lists.concat [+                    Lists.filter (\group -> Logic.not (Lists.isEmpty group)) (Lists.concat [                       [                         commentStmts,                         importStmts,@@ -933,7 +934,7 @@                     Core.bindingTypeScheme = (Just ts)}           isComplex = Predicates.isComplexBinding tc binding           isTrivial = Predicates.isTrivialTerm term-      in (Logic.ifElse (Logic.and isComplex (Logic.not isTrivial)) (Logic.ifElse (Logic.and (Logic.not topLevel) (Lists.null params)) (Eithers.bind (encodeTermInline cx env2 False term) (\bodyExpr ->+      in (Logic.ifElse (Logic.and isComplex (Logic.not isTrivial)) (Logic.ifElse (Logic.and (Logic.not topLevel) (Lists.isEmpty params)) (Eithers.bind (encodeTermInline cx env2 False term) (\bodyExpr ->         let pyName = PythonNames.encodeName False Util.CaseConventionLowerSnake env2 name             lazyExpr = makeLazy bodyExpr         in (Right (Utils.annotatedStatement comment (Utils.assignmentStatement pyName lazyExpr))))) (Eithers.bind (Eithers.mapList (encodeBindingAs cx env2) bindings) (\bindingStmts -> functionDefinitionToExpr cx env2 name tparams params body doms mcod comment bindingStmts))) (Eithers.bind (encodeTermInline cx env2 False body) (\bodyExpr ->@@ -978,7 +979,7 @@                         PythonEnvironment.pythonEnvironmentOverlaySubs = (PythonEnvironment.pythonEnvironmentOverlaySubs innerEnv0)}           in (Eithers.bind (encodeTermInline cx innerEnv False innerBody) (\pbody ->             let pparams = Lists.map (PythonNames.encodeName False Util.CaseConventionLowerSnake innerEnv) params-            in (Logic.ifElse (Lists.null bindings) (Right (makeUncurriedLambda pparams pbody)) (Eithers.bind (Eithers.mapList (encodeBindingAsAssignment cx False innerEnv) bindings) (\pbindingExprs ->+            in (Logic.ifElse (Lists.isEmpty bindings) (Right (makeUncurriedLambda pparams pbody)) (Eithers.bind (Eithers.mapList (encodeBindingAsAssignment cx False innerEnv) bindings) (\pbindingExprs ->               let pbindingStarExprs = Lists.map (\ne -> Syntax.StarNamedExpressionSimple ne) pbindingExprs                   pbodyStarExpr = Utils.pyExpressionToPyStarNamedExpression pbody                   tupleElements = Lists.concat2 pbindingStarExprs [@@ -1039,7 +1040,7 @@         Core.TermLet v0 ->           let bindings = Core.letBindings v0               body = Core.letBody v0-          in (Logic.ifElse (Lists.null bindings) (encodeTermInline cx env False body) (withLetInline env v0 (\innerEnv -> Eithers.bind (Eithers.mapList (encodeBindingAsAssignment cx False innerEnv) bindings) (\pbindingExprs -> Eithers.bind (encodeTermInline cx innerEnv False body) (\pbody ->+          in (Logic.ifElse (Lists.isEmpty bindings) (encodeTermInline cx env False body) (withLetInline env v0 (\innerEnv -> Eithers.bind (Eithers.mapList (encodeBindingAsAssignment cx False innerEnv) bindings) (\pbindingExprs -> Eithers.bind (encodeTermInline cx innerEnv False body) (\pbody ->             let pbindingStarExprs = Lists.map (\ne -> Syntax.StarNamedExpressionSimple ne) pbindingExprs                 pbodyStarExpr = Utils.pyExpressionToPyStarNamedExpression pbody                 tupleElements = Lists.concat2 pbindingStarExprs [@@ -1113,7 +1114,7 @@                     bindings = Typing.functionStructureBindings fs                     innerBody = Typing.functionStructureBody fs                     env2 = Typing.functionStructureEnvironment fs-                in (Logic.ifElse (Lists.null bindings) (Eithers.bind (encodeTermInline cx env False term) (\expr -> Right [+                in (Logic.ifElse (Lists.isEmpty bindings) (Eithers.bind (encodeTermInline cx env False term) (\expr -> Right [                   Utils.returnSingle expr])) (Eithers.bind (Eithers.mapList (encodeBindingAs cx env2) bindings) (\bindingStmts -> Eithers.bind (encodeTermMultiline cx env2 innerBody) (\bodyStmts -> Right (Lists.concat2 bindingStmts bodyStmts))))))           gathered = Analysis.gatherApplications term           args = Pairs.first gathered@@ -1256,7 +1257,7 @@ -- | Encode a type to a Python expression, quoting if the type has free variables encodeTypeQuoted :: PythonEnvironment.PythonEnvironment -> Core.Type -> Either t0 Syntax.Expression encodeTypeQuoted env typ =-    Eithers.bind (encodeType env typ) (\pytype -> Right (Logic.ifElse (Sets.null (Variables.freeVariablesInType typ)) pytype (Utils.doubleQuotedString (Serialization.printExpr (Serde.expressionToExpr pytype)))))+    Eithers.bind (encodeType env typ) (\pytype -> Right (Logic.ifElse (Sets.isEmpty (Variables.freeVariablesInType typ)) pytype (Utils.doubleQuotedString (Serialization.printExpr (Serde.expressionToExpr pytype)))))  -- | Encode a union elimination as an inline conditional chain (isinstance-based ternary) encodeUnionEliminationInline :: Typing.InferenceContext -> PythonEnvironment.PythonEnvironment -> Core.CaseStatement -> Syntax.Expression -> Either Errors.Error Syntax.Expression@@ -1342,7 +1343,7 @@           tparamNames = findTypeParams env ftype           tparams = Lists.map PythonNames.encodeTypeVariable tparamNames           namePrim = Utils.pyNameToPyPrimary (PythonNames.variantName False env unionName fname)-      in (Logic.ifElse (Lists.null tparams) namePrim (+      in (Logic.ifElse (Lists.isEmpty tparams) namePrim (         let tparamExprs = Lists.map Utils.pyNameToPyExpression tparams         in (Utils.primaryWithExpressionSlices namePrim tparamExprs))) @@ -1390,12 +1391,12 @@           asFunctionCall =                   Utils.functionCall (Utils.pyNameToPyPrimary (PythonNames.encodeName True Util.CaseConventionLowerSnake env name)) args           asLazyCall = Utils.functionCall (Utils.pyExpressionToPyPrimary (lazyDotGet asVariable)) args-      in (Logic.ifElse (Logic.not (Lists.null args)) (Logic.ifElse (Sets.member name inlineVars) (Right asLazyCall) (Optionals.match (Lexical.lookupPrimitive g name) (Right asFunctionCall) (\prim ->+      in (Logic.ifElse (Logic.not (Lists.isEmpty args)) (Logic.ifElse (Sets.member name inlineVars) (Right asLazyCall) (Optionals.match (Lexical.lookupPrimitive g name) (Right asFunctionCall) (\prim ->         let primArity = Arity.primitiveArity prim         in (Logic.ifElse (Equality.equal primArity (Lists.length args)) (Right asFunctionCall) (           let numRemaining = Math.sub primArity (Lists.length args)               remainingParams =-                      Lists.map (\i -> Syntax.Name (Strings.concat2 "x" (Literals.showInt32 i))) (Math.range 1 (Math.add numRemaining 1))+                      Lists.map (\i -> Syntax.Name (Strings.concat2 "x" (Literals.printInt32 i))) (Math.range 1 (Math.add numRemaining 1))               remainingExprs =                       Lists.map (\n -> Syntax.ExpressionSimple (Syntax.Disjunction [                         Syntax.Conjunction [@@ -1425,31 +1426,31 @@         let elTrivial1 = Predicates.isTrivialTerm (Core.bindingTerm el)         in (Optionals.match (Core.bindingTypeScheme el) (Right asVariable) (\ts -> Logic.ifElse (Logic.and (Logic.and (Equality.equal (Arity.typeSchemeArity ts) 0) (Predicates.isComplexBinding tc el)) (Logic.not elTrivial1)) (Right asFunctionCall) (           let asFunctionRef =-                  Logic.ifElse (Logic.not (Lists.null (Core.typeSchemeVariables ts))) (makeSimpleLambda (Arity.typeArity (Core.typeSchemeBody ts)) asVariable) asVariable+                  Logic.ifElse (Logic.not (Lists.isEmpty (Core.typeSchemeVariables ts))) (makeSimpleLambda (Arity.typeArity (Core.typeSchemeBody ts)) asVariable) asVariable           in (Right asFunctionRef)))))) (\prim ->         let primArity = Arity.primitiveArity prim         in (Logic.ifElse (Equality.equal primArity 0) (Right asFunctionCall) (           let ts = Scoping.termSignatureToTypeScheme (Packaging.primitiveDefinitionSignature (Graph.primitiveDefinition prim))               asFunctionRef =-                      Logic.ifElse (Logic.not (Lists.null (Core.typeSchemeVariables ts))) (makeSimpleLambda (Arity.typeArity (Core.typeSchemeBody ts)) asVariable) asVariable+                      Logic.ifElse (Logic.not (Lists.isEmpty (Core.typeSchemeVariables ts))) (makeSimpleLambda (Arity.typeArity (Core.typeSchemeBody ts)) asVariable) asVariable           in (Right asFunctionRef))))))) (\typ -> Logic.ifElse (Sets.member name tcLambdaVars) (Right asVariable) (Logic.ifElse (Sets.member name inlineVars) (         let unwrapped = lazyDotGet asVariable             asFunctionRef =-                    Logic.ifElse (Logic.not (Sets.null (Variables.freeVariablesInType typ))) (makeSimpleLambda (Arity.typeArity typ) unwrapped) unwrapped+                    Logic.ifElse (Logic.not (Sets.isEmpty (Variables.freeVariablesInType typ))) (makeSimpleLambda (Arity.typeArity typ) unwrapped) unwrapped         in (Right asFunctionRef)) (Logic.ifElse (Logic.not (Maps.member name tcMetadata)) (Optionals.match (Lexical.lookupBinding g name) (         let asFunctionRef =-                Logic.ifElse (Logic.not (Sets.null (Variables.freeVariablesInType typ))) (makeSimpleLambda (Arity.typeArity typ) asVariable) asVariable+                Logic.ifElse (Logic.not (Sets.isEmpty (Variables.freeVariablesInType typ))) (makeSimpleLambda (Arity.typeArity typ) asVariable) asVariable         in (Right asFunctionRef)) (\el ->         let elTrivial = Predicates.isTrivialTerm (Core.bindingTerm el)         in (Optionals.match (Core.bindingTypeScheme el) (Logic.ifElse (Logic.and (Equality.equal (Arity.typeArity typ) 0) (Logic.not elTrivial)) (Right asFunctionCall) (           let asFunctionRef =-                  Logic.ifElse (Logic.not (Sets.null (Variables.freeVariablesInType typ))) (makeSimpleLambda (Arity.typeArity typ) asVariable) asVariable+                  Logic.ifElse (Logic.not (Sets.isEmpty (Variables.freeVariablesInType typ))) (makeSimpleLambda (Arity.typeArity typ) asVariable) asVariable           in (Right asFunctionRef))) (\ts -> Logic.ifElse (Logic.and (Logic.and (Equality.equal (Arity.typeArity typ) 0) (Predicates.isComplexBinding tc el)) (Logic.not elTrivial)) (Right asFunctionCall) (           let asFunctionRef =-                  Logic.ifElse (Logic.not (Sets.null (Variables.freeVariablesInType typ))) (makeSimpleLambda (Arity.typeArity typ) asVariable) asVariable+                  Logic.ifElse (Logic.not (Sets.isEmpty (Variables.freeVariablesInType typ))) (makeSimpleLambda (Arity.typeArity typ) asVariable) asVariable           in (Right asFunctionRef)))))) (Logic.ifElse (Logic.and (Equality.equal (Arity.typeArity typ) 0) (Predicates.isComplexVariable tc name)) (Right asFunctionCall) (         let asFunctionRef =-                Logic.ifElse (Logic.not (Sets.null (Variables.freeVariablesInType typ))) (makeSimpleLambda (Arity.typeArity typ) asVariable) asVariable+                Logic.ifElse (Logic.not (Sets.isEmpty (Variables.freeVariablesInType typ))) (makeSimpleLambda (Arity.typeArity typ) asVariable) asVariable         in (Right asFunctionRef))))))))  -- | Encode a wrapped type (newtype) to a Python class definition@@ -1564,7 +1565,7 @@         Core.TypeLiteral v0 -> case v0 of           Core.LiteralTypeDecimal -> setMetaUsesDecimal metaWithSubtypes True           _ -> metaWithSubtypes-        Core.TypeUnion v0 -> Logic.ifElse (Predicates.isEnumRowType v0) (setMetaUsesEnum metaWithSubtypes True) (Logic.ifElse (Logic.not (Lists.null v0)) (setMetaUsesNode metaWithSubtypes True) metaWithSubtypes)+        Core.TypeUnion v0 -> Logic.ifElse (Predicates.isEnumRowType v0) (setMetaUsesEnum metaWithSubtypes True) (Logic.ifElse (Logic.not (Lists.isEmpty v0)) (setMetaUsesNode metaWithSubtypes True) metaWithSubtypes)         Core.TypeForall v0 ->           let body = Core.forallTypeBody v0               metaForWrap = digForWrap isTermAnnot metaWithSubtypes body@@ -1573,7 +1574,7 @@             _ -> metaForWrap         Core.TypeRecord v0 ->           let hasAnnotated = Lists.foldl (\b -> \ft -> Logic.or b (Annotations.hasTypeDescription (Core.fieldTypeType ft))) False v0-              meta1 = Logic.ifElse (Lists.null v0) metaWithSubtypes (setMetaUsesDataclass metaWithSubtypes True)+              meta1 = Logic.ifElse (Lists.isEmpty v0) metaWithSubtypes (setMetaUsesDataclass metaWithSubtypes True)           in (Logic.ifElse hasAnnotated (setMetaUsesAnnotated meta1 True) meta1)         Core.TypeWrap _ -> Logic.ifElse isTermAnnot metaWithSubtypes (setMetaUsesNode metaWithSubtypes True)         _ -> metaWithSubtypes@@ -1624,7 +1625,7 @@                 Syntax.paramNoDefaultParametersParamNoDefault = pyArgs,                 Syntax.paramNoDefaultParametersParamWithDefault = [],                 Syntax.paramNoDefaultParametersStarEtc = Nothing})-          isTCO = Logic.and (Logic.not (Lists.null args)) (Analysis.isSelfTailRecursive name body)+          isTCO = Logic.and (Logic.not (Lists.isEmpty args)) (Analysis.isSelfTailRecursive name body)       in (Eithers.bind (Logic.ifElse isTCO (Eithers.bind (encodeTermMultilineTCO cx env name args body) (\tcoStmts ->         let trueExpr = Syntax.NamedExpressionSimple (Utils.pyAtomToPyExpression Syntax.AtomTrue)             whileBody = Utils.indentedBlock Nothing [@@ -1640,7 +1641,7 @@         Lists.concat2 prefixes stmts])))) (\block -> Eithers.bind (Optionals.match mcod (Right Nothing) (\cod -> Eithers.bind (encodeType env cod) (\pytyp -> Right (Just pytyp)))) (\mreturnType ->         let pyTparams =                 Logic.ifElse useInlineTypeParams (Lists.map (\arg_ -> Utils.pyNameToPyTypeParameter (PythonNames.encodeTypeVariable arg_)) tparams) []-            isThunk = Lists.null args+            isThunk = Lists.isEmpty args             mDecorators = Logic.ifElse isThunk (Just (Syntax.Decorators [                   lruCacheDecorator])) Nothing             pyName = PythonNames.encodeName False Util.CaseConventionLowerSnake env name@@ -1686,12 +1687,12 @@           result = Lists.foldl addDef start defs           tvars = PythonEnvironment.pythonModuleMetadataTypeVariables result           result2 = setMetaUsesCast True (setMetaUsesLruCache True result)-      in (setMetaUsesTypeVar result2 (Logic.not (Sets.null tvars)))+      in (setMetaUsesTypeVar result2 (Logic.not (Sets.isEmpty tvars)))  -- | Create Generic[...] argument expression for class definition genericArg :: [Core.Name] -> Maybe Syntax.Expression genericArg tparamList =-    Logic.ifElse (Lists.null tparamList) Nothing (Just (Utils.pyPrimaryToPyExpression (Utils.primaryWithExpressionSlices (Syntax.PrimarySimple (Syntax.AtomName (Syntax.Name "Generic"))) (Lists.map (\n -> Syntax.ExpressionSimple (Syntax.Disjunction [+    Logic.ifElse (Lists.isEmpty tparamList) Nothing (Just (Utils.pyPrimaryToPyExpression (Utils.primaryWithExpressionSlices (Syntax.PrimarySimple (Syntax.AtomName (Syntax.Name "Generic"))) (Lists.map (\n -> Syntax.ExpressionSimple (Syntax.Disjunction [       Syntax.Conjunction [         Syntax.InversionSimple (Syntax.Comparison {           Syntax.comparisonLhs = Syntax.BitwiseOr {@@ -1784,7 +1785,7 @@ -- | Check whether a list of definitions contains any type definitions isTypeModuleCheck :: [Packaging.Definition] -> Bool isTypeModuleCheck defs =-    Logic.not (Lists.null (Lists.filter (\d -> case d of+    Logic.not (Lists.isEmpty (Lists.filter (\d -> case d of       Packaging.DefinitionType _ -> True       _ -> False) defs)) @@ -1846,7 +1847,7 @@ makeSimpleLambda :: Int -> Syntax.Expression -> Syntax.Expression makeSimpleLambda arity lhs = -      let args = Lists.map (\i -> Syntax.Name (Strings.concat2 "x" (Literals.showInt32 i))) (Math.range 1 (Math.add arity 1))+      let args = Lists.map (\i -> Syntax.Name (Strings.concat2 "x" (Literals.printInt32 i))) (Math.range 1 (Math.add arity 1))       in (Logic.ifElse (Equality.equal arity 0) lhs (Syntax.ExpressionLambda (Syntax.Lambda {         Syntax.lambdaParams = Syntax.LambdaParameters {           Syntax.lambdaParametersSlashNoDefault = Nothing,@@ -1965,7 +1966,7 @@                   Optionals.givens (Lists.map (\p ->                     let modName = Pairs.first p                         symbols = Optionals.givens (Pairs.second p)-                    in (Logic.ifElse (Lists.null symbols) Nothing (Just (modName, symbols)))) pairs)+                    in (Logic.ifElse (Lists.isEmpty symbols) Nothing (Just (modName, symbols)))) pairs)       in (Lists.map (\p -> standardImportStatement (Pairs.first p) (Pairs.second p)) simplified)  -- | Convert a Hydra module to Python source files
src/main/haskell/Hydra/Python/Environment.hs view
@@ -12,6 +12,7 @@ import qualified Hydra.Util as Util import Prelude hiding  (Enum, Ordering, decodeFloat, encodeFloat, fail, lines, map, pure, sum, unlines) import qualified Data.Scientific as Sci+import Data.Void import qualified Data.Map as M import qualified Data.Set as S 
src/main/haskell/Hydra/Python/Language.hs view
@@ -33,6 +33,7 @@ import qualified Hydra.Variants as Variants import Prelude hiding  (Enum, Ordering, decodeFloat, encodeFloat, fail, lines, map, pure, sum, unlines) import qualified Data.Scientific as Sci+import Data.Void import qualified Data.Set as S  -- | Language constraints for Python 3
src/main/haskell/Hydra/Python/Names.hs view
@@ -43,6 +43,7 @@ import qualified Hydra.Variants as Variants import Prelude hiding  (Enum, Ordering, decodeFloat, encodeFloat, fail, lines, map, pure, sum, unlines) import qualified Data.Scientific as Sci+import Data.Void import qualified Data.Map as M import qualified Data.Set as S 
src/main/haskell/Hydra/Python/Pyproject.hs view
@@ -8,6 +8,7 @@ import qualified Hydra.Packaging as Packaging import Prelude hiding  (Enum, Ordering, decodeFloat, encodeFloat, fail, lines, map, pure, sum, unlines) import qualified Data.Scientific as Sci+import Data.Void  data PyProjectBuildConfiguration =   PyProjectBuildConfiguration {
src/main/haskell/Hydra/Python/Serde.hs view
@@ -41,6 +41,7 @@ import qualified Hydra.Variants as Variants import Prelude hiding  (Enum, Ordering, decodeFloat, encodeFloat, fail, lines, map, pure, sum, unlines) import qualified Data.Scientific as Sci+import Data.Void  -- | Serialize an annotated RHS annotatedRhsToExpr :: Syntax.AnnotatedRhs -> Ast.Expr@@ -275,7 +276,7 @@        let lhs = Syntax.comparisonLhs cmp           rhs = Syntax.comparisonRhs cmp-      in (Logic.ifElse (Lists.null rhs) (bitwiseOrToExpr lhs) (Serialization.spaceSep (Lists.cons (bitwiseOrToExpr lhs) (Lists.map compareOpBitwiseOrPairToExpr rhs))))+      in (Logic.ifElse (Lists.isEmpty rhs) (bitwiseOrToExpr lhs) (Serialization.spaceSep (Lists.cons (bitwiseOrToExpr lhs) (Lists.map compareOpBitwiseOrPairToExpr rhs))))  -- | Serialize a compound (multi-line) Python statement compoundStatementToExpr :: Syntax.CompoundStatement -> Ast.Expr@@ -400,7 +401,7 @@           block = Syntax.functionDefRawBlock fdr           asyncKw = Logic.ifElse async_ (Just (Serialization.cst "async")) Nothing           tparamPart =-                  Logic.ifElse (Lists.null tparams) Nothing (Just (Serialization.bracketList Serialization.inlineStyle (Lists.map typeParameterToExpr tparams)))+                  Logic.ifElse (Lists.isEmpty tparams) Nothing (Just (Serialization.bracketList Serialization.inlineStyle (Lists.map typeParameterToExpr tparams)))           paramPart = Optionals.map parametersToExpr params           retPart =                   Optionals.map (\t -> Serialization.spaceSep [@@ -641,9 +642,9 @@ numberToExpr :: Syntax.Number -> Ast.Expr numberToExpr num =     case num of-      Syntax.NumberFloat v0 -> Serialization.cst (pythonFloatLiteralText (Literals.showFloat64 v0))-      Syntax.NumberImaginary v0 -> Serialization.cst (Strings.concat2 (pythonFloatLiteralText (Literals.showFloat64 v0)) "j")-      Syntax.NumberInteger v0 -> Serialization.cst (Literals.showBigint v0)+      Syntax.NumberFloat v0 -> Serialization.cst (pythonFloatLiteralText (Literals.printFloat64 v0))+      Syntax.NumberImaginary v0 -> Serialization.cst (Strings.concat2 (pythonFloatLiteralText (Literals.printFloat64 v0)) "j")+      Syntax.NumberInteger v0 -> Serialization.cst (Literals.printBigint v0)  -- | Serialize an or pattern orPatternToExpr :: Syntax.OrPattern -> Ast.Expr@@ -1013,7 +1014,7 @@           alias =                   Serialization.noSep (Optionals.givens [                     Just (nameToExpr name),-                    (Logic.ifElse (Lists.null tparams) Nothing (Just (Serialization.bracketList Serialization.inlineStyle (Lists.map typeParameterToExpr tparams))))])+                    (Logic.ifElse (Lists.isEmpty tparams) Nothing (Just (Serialization.bracketList Serialization.inlineStyle (Lists.map typeParameterToExpr tparams))))])       in (Serialization.spaceSep [         Serialization.cst "type",         alias,
src/main/haskell/Hydra/Python/Syntax.hs view
@@ -8,6 +8,7 @@ import qualified Hydra.Core as Core import Prelude hiding  (Enum, Ordering, decodeFloat, encodeFloat, fail, lines, map, pure, sum, unlines) import qualified Data.Scientific as Sci+import Data.Void  data AnnotatedStatement =   AnnotatedStatement {
src/main/haskell/Hydra/Python/Testing.hs view
@@ -42,6 +42,7 @@ import qualified Hydra.Variants as Variants import Prelude hiding  (Enum, Ordering, decodeFloat, encodeFloat, fail, lines, map, pure, sum, unlines) import qualified Data.Scientific as Sci+import Data.Void  -- | Build the complete Python test module content buildPythonTestModule :: t0 -> Testing.TestGroup -> String -> String@@ -74,7 +75,7 @@         Testing.TestCaseUniversal v0 ->           let actual_ = Testing.universalTestCaseActual v0 ()               expected_ = Testing.universalTestCaseExpected v0 ()-              fullName = Logic.ifElse (Lists.null groupPath) name_ (Strings.join "__" (Lists.concat2 groupPath [+              fullName = Logic.ifElse (Lists.isEmpty groupPath) name_ (Strings.join "__" (Lists.concat2 groupPath [                     name_]))               formattedName = formatPythonTestName fullName           in (Right [
src/main/haskell/Hydra/Python/Utils.hs view
@@ -42,6 +42,7 @@ import qualified Hydra.Variants as Variants import Prelude hiding  (Enum, Ordering, decodeFloat, encodeFloat, fail, lines, map, pure, sum, unlines) import qualified Data.Scientific as Sci+import Data.Void import qualified Data.Set as S  -- | Annotate an expression with an optional comment using Annotated[]@@ -100,7 +101,7 @@           sumRhs = Syntax.sumRhs shiftRhs           termLhs = Syntax.termLhs sumRhs           termRhs = Syntax.termRhs sumRhs-      in (Logic.ifElse (Logic.not (Lists.null rhs)) Nothing (Logic.ifElse (Optionals.isGiven orLhs) Nothing (Logic.ifElse (Optionals.isGiven xorLhs) Nothing (Logic.ifElse (Optionals.isGiven andLhs) Nothing (Logic.ifElse (Optionals.isGiven shiftLhs) Nothing (Logic.ifElse (Optionals.isGiven sumLhs) Nothing (Logic.ifElse (Optionals.isGiven termLhs) Nothing (case termRhs of+      in (Logic.ifElse (Logic.not (Lists.isEmpty rhs)) Nothing (Logic.ifElse (Optionals.isGiven orLhs) Nothing (Logic.ifElse (Optionals.isGiven xorLhs) Nothing (Logic.ifElse (Optionals.isGiven andLhs) Nothing (Logic.ifElse (Optionals.isGiven shiftLhs) Nothing (Logic.ifElse (Optionals.isGiven sumLhs) Nothing (Logic.ifElse (Optionals.isGiven termLhs) Nothing (case termRhs of         Syntax.FactorSimple v0 -> decodePyPowerToPyPrimary v0         _ -> Nothing)))))))) @@ -191,8 +192,8 @@        let commentGroup = Optionals.match mcomment [] (\s -> [             commentStatement s])-          groups = Lists.filter (\g -> Logic.not (Lists.null g)) (Lists.cons commentGroup stmts)-      in (Logic.ifElse (Lists.null groups) (Syntax.BlockIndented [+          groups = Lists.filter (\g -> Logic.not (Lists.isEmpty g)) (Lists.cons commentGroup stmts)+      in (Logic.ifElse (Lists.isEmpty groups) (Syntax.BlockIndented [         [           Syntax.StatementSimple [             pyExpressionToPySimpleStatement (pyAtomToPyExpression Syntax.AtomEllipsis)]]]) (Syntax.BlockIndented groups))@@ -215,7 +216,7 @@       let build =               \prev -> \ps -> Optionals.match (Lists.uncons ps) (Syntax.BitwiseOr {                 Syntax.bitwiseOrLhs = prev,-                Syntax.bitwiseOrRhs = (pyPrimaryToPyBitwiseXor (Syntax.PrimarySimple Syntax.AtomEllipsis))}) (\p -> Logic.ifElse (Lists.null (Pairs.second p)) (Syntax.BitwiseOr {+                Syntax.bitwiseOrRhs = (pyPrimaryToPyBitwiseXor (Syntax.PrimarySimple Syntax.AtomEllipsis))}) (\p -> Logic.ifElse (Lists.isEmpty (Pairs.second p)) (Syntax.BitwiseOr {                 Syntax.bitwiseOrLhs = prev,                 Syntax.bitwiseOrRhs = (pyPrimaryToPyBitwiseXor (Pairs.first p))}) (build (Just (Syntax.BitwiseOr {                 Syntax.bitwiseOrLhs = prev,@@ -629,7 +630,7 @@                         getItemMethod]])})           docStmt = pyExpressionToPyStatement (tripleQuotedString docString)           bodyGroups =-                  Logic.ifElse (Lists.null extraStmts) (+                  Logic.ifElse (Lists.isEmpty extraStmts) (                     let passStmt = pySimpleStatementToPyStatement Syntax.SimpleStatementPass                     in [                       [