Skip to content

Issue running CaliforniaHousing.md #6

@kutyel

Description

@kutyel

Hey!

Loved your presentation at Zurihac today! 🙌🏻 I run into the following issue while running the code:

dataframe-operations 1.0.1.1 fails to compile against dataframe-core 1.0.2.0 (ambiguous record

fields)

Summary

dataframe-core 1.0.2.0 (released 2026-06-06) breaks dataframe-operations 1.0.1.1,
and the existing bounds let cabal pick the broken combination. Anyone with a fresh
Hackage index who ends up with dataframe 2.1.0.0/2.1.0.1 (or any plan with
dataframe-operations < 1.1) hits ~28 Ambiguous occurrence errors in
DataFrame.Functions.

Error

[ 2 of 17] Compiling DataFrame.Functions ( src/DataFrame/Functions.hs, ... )
src/DataFrame/Functions.hs:46:22: error:
    Ambiguous occurrence ‘unaryFn’
    It could refer to
       either ‘DataFrame.Internal.Expression.unaryFn’,
              imported from ‘DataFrame.Internal.Expression’ at src/DataFrame/Functions.hs:16:1-36
           or the field ‘unaryFn’ of record ‘UnUDF’,
              imported from ‘DataFrame.Internal.Expression’ at src/DataFrame/Functions.hs:16:1-36
   |
46 |     Unary (MkUnaryOp{unaryFn = f, unaryName = "unaryUdf", unarySymbol = Nothing})
   |                      ^^^^^^^

(…and the same for unaryName, unarySymbol, binaryFn, binaryName,
binarySymbol, binaryCommutative, binaryPrecedence at every
MkUnaryOp{…} / MkBinaryOp{…} construction site in DataFrame/Functions.hs.)

Root cause

dataframe-core 1.0.2.0 refactored DataFrame.Internal.Expression to introduce
open typeclasses UnaryOp / BinaryOp whose method names intentionally match
the UnUDF / BinUDF record fields (unaryFn, unaryName, unarySymbol,
binaryFn, …). The defining module compiles because it enables
NoFieldSelectors + DisambiguateRecordFields.

However, dataframe-operations 1.0.1.1's DataFrame.Functions imports
DataFrame.Internal.Expression unqualified and does not enable
DisambiguateRecordFields, so every record construction like
MkUnaryOp{unaryFn = f, …} now sees both the class method and the field and
fails as ambiguous.

The fix already exists in dataframe-operations 1.1.0.1 (released the same
day), and dataframe 2.1.0.2 correctly requires dataframe-operations ^>= 1.1.
The problem is the old releases remain installable in a broken configuration.

Why the solver picks the broken plan

  • dataframe-operations 1.0.1.1 declares dataframe-core ^>= 1.0, which wrongly
    admits 1.0.2.0. There is no Hackage revision excluding it.
  • dataframe 2.1.0.0 / 2.1.0.1 declare dataframe-operations ^>= 1.0
    (i.e. < 1.1), so any plan that selects those versions is forced onto the
    broken ops + new core combination.
  • dataframe-hasktorch 0.2.0.0 declares dataframe-operations ^>= 1.0
    (i.e. < 1.1). This makes the breakage unavoidable even without pinning:
    a build-depends of dataframe, dataframe-hasktorch conflicts with
    dataframe 2.1.0.2 (needs ops ^>= 1.1), so the solver backtracks to
    dataframe 2.1.0.x + dataframe-operations 1.0.1.1 + dataframe-core 1.0.2.0
    → compile failure.

Reproduction

With a Hackage index from 2026-06-06 or later (GHC 9.6.7, cabal 3.14.1.1):

cabal install --lib "dataframe ==2.1.0.0"
# or, with no pin at all:
cabal install --lib dataframe dataframe-hasktorch

Both resolve to dataframe-core-1.0.2.0 + dataframe-operations-1.0.1.1 and
fail compiling DataFrame.Functions as above.

Suggested fixes

  1. Hackage metadata revision on dataframe-operations 1.0.1.1 (and any other
    < 1.1 release with the same bound): constrain dataframe-core < 1.0.2.
    This alone removes every broken install plan.
  2. Same revision treatment for any other dataframe-* sub-package that uses the
    MkUnaryOp/MkBinaryOp record syntax with dataframe-core ^>= 1.0 and no
    DisambiguateRecordFields.
  3. dataframe-hasktorch: release a version allowing
    dataframe-operations ^>= 1.1 so it composes with dataframe 2.1.0.2.

Workaround for users

Add an explicit pin on the old core, e.g.:

build-depends: dataframe ==2.1.0.0, dataframe-core ==1.0.1.1, dataframe-hasktorch ==0.2.0.0

or, when not using dataframe-hasktorch, simply allow the solver to pick
dataframe 2.1.0.2.

Versions involved

Package Version Uploaded Status
dataframe-core 1.0.2.0 2026-06-06 introduces the class/field name overlap
dataframe-operations 1.0.1.1 (pre-existing) broken against core 1.0.2.0; bound too loose
dataframe-operations 1.1.0.1 2026-06-06 fixed
dataframe 2.1.0.0 / 2.1.0.1 2026-05-16 / — force ops < 1.1 → broken plans
dataframe 2.1.0.2 2026-06-06 fixed (requires ops ^>= 1.1)
dataframe-hasktorch 0.2.0.0 (latest) still requires ops < 1.1 → blocks fixed plans

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions