Skip to content

fix(fjl)!: #152-haskell-parity align list methods with Haskell - #156

Open
elycruz wants to merge 2 commits into
mainfrom
152-haskell-parity
Open

elycruz wants to merge 2 commits into
mainfrom
152-haskell-parity

Conversation

@elycruz

@elycruz elycruz commented Nov 4, 2026

Copy link
Copy Markdown
Member

Closes #152. Compares every exported fjl method that has a Haskell counterpart against base-4.22.0.0, and fixes the differences that weren't deliberate. The full inventory is in md/issues/HASKELL_PARITY.md, and every breaking change is in md/MIGRATION_V2.md.

GHC wasn't available, so expected values come from the examples and laws in the pinned docs, not from running Haskell.

Rules applied

  • Match Haskell's results, result order and empty-input behaviour, but keep native and fjl argument and callback order, so foldr stays op(acc, x, i, xs).
  • Value searches take the list last, including the ones that wrap native methods.
  • A method that returns a variation of its list returns the list when nothing changes, so stripPrefix keeps returning it rather than undefined.

Breaking changes

Most of these change results without throwing, so they're listed under "Check these first" in the migration notes.

Method Before After
elem, notElem, elemIndex, includes, indexOf, lastIndexOf, and their $ forms (xs, x) (x, xs)
scanr, scanr1 fn(x, acc, i, xs) fn(acc, x, i, xs), like foldr
repeat, cycle, iterate, replicateIter, unfoldrIter Yielded growing lists Yield items: take(3, repeat(17)) gives [17, 17, 17]
cycle([]) Yielded [] forever Throws on first pull
take Pulled n + 1 items Pulls exactly n
mapAccumR Reversed its result list Keeps input order
groupBy Compared with the previous item Compares with the group's first item
nubBy pred(item, kept) pred(kept, item)
splitAt A negative position counted from the end [[], xs]
intercalate(',', []) [] ''
lines lines('one\n') gave ['one', ''] ['one'], and lines('') gives []
words Split on each space or tab Splits on runs of whitespace, and ignores it at the ends
unlines 'a\nb' 'a\nb\n'
unionBy pred(accumulatedList, x) eq(a, b)
union NaN equalled itself Compares with ===
difference Removed every occurrence Removes one per item, so (xs ++ ys) \\ xs == ys holds
nub, nubBy, union, unionBy, intersect, intersectBy, difference Gave an array or threw for strings Give a string

Bugs fixed

  • replicate threw on a negative count.
  • concat([]) returned undefined.
  • remove, removeBy and removeFirstsBy couldn't match a surrogate pair in a string.
  • fjl-validator's defaultValueObscurer returned "*,*,*,**,*,*,**,*,*,*" for 'abc', and now gives "***". No test checked its output, so this adds one.

Worth checking

  • Old-order calls often fail silently: includes(xs, 'a') with a string as xs checks whether 'a' contains that string and returns false.
  • lines: still counts \r, \r\n and \n\r as one line break, as its doc comment promised. Haskell would keep the \r.
  • complement: has no counterpart, so it still removes every occurrence, unlike difference.
  • Deliberate differences: doc comments cover the ones v2.0 - Check Haskell parity for methods with Haskell counterparts #152 names, and the findings tables cover the rest.

Follow-ups

Testing

All 1,632 tests pass, and the build and lint have no errors. tsc still reports errors in fjl-labs and in fjl-validator-recaptcha's tests, neither of which this changes. New tests check the documented examples and laws where the docs give them.

🤖 Generated with Claude Code

elycruz and others added 2 commits November 4, 2026 13:17
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
BREAKING CHANGE: value searches (elem, notElem, elemIndex, includes,
indexOf, lastIndexOf) now take (x, xs). scanr and scanr1 call
fn(acc, x, i, xs). Generators yield items, not growing lists. unionBy
takes eq(a, b). difference removes one occurrence per item. lines,
words, unlines, mapAccumR, groupBy, nubBy, splitAt, intercalate and take
change results. See md/MIGRATION_V2.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

v2.0 - Check Haskell parity for methods with Haskell counterparts

1 participant