Skip to content

Instantly share code, notes, and snippets.

@andreasabel
Last active December 8, 2021 21:02
Show Gist options
  • Save andreasabel/0718ff2b6ca515bba5971748aea6b48f to your computer and use it in GitHub Desktop.
Save andreasabel/0718ff2b6ca515bba5971748aea6b48f to your computer and use it in GitHub Desktop.
Additions to Haskell's `Prelude` since `base-4.0.0.0`

Additions to Haskell's Prelude since base-4.0.0.0

base version additions
4.8.0.0 *> <$ <$> <* <*> Applicative Foldable Monoid Traversable Word foldMap mappend mconcat mempty pure sequenceA traverse
4.9.0.0 errorWithoutStackTrace
4.11.0.0 <> Semigroup
4.13.0.0 MonadFail
# Andreas Abel, 2021-12-08
# Extract 'since' information for Prelude memebership from sources.
# List functions
# From https://riptutorial.com/makefile/example/23643/zipping-lists, example:
#
# func = $1-$2
#
# all:
# @echo $(call zipWith,func,$(LIST1),$(LIST2))
#
tail = $(wordlist 2,$(words $1),$1)
zipWith = $(and $(strip $2),$(strip $3),$(call \
$1,$(firstword $2),$(firstword $3)) $(call \
zipWith,$1,$(call tail,$2),$(call tail,$3)))
# Variables
# working directories
dirs = Prelude only-idents word-lists added
# base versions
versions = \
4.0.0.0 4.1.0.0 4.2.0.0 4.2.0.1 4.2.0.2 \
4.3.0.0 4.3.1.0 4.4.0.0 4.4.1.0 4.5.0.0 4.5.1.0 \
4.6.0.0 4.6.0.1 4.7.0.0 4.7.0.1 4.7.0.2 4.8.0.0 4.8.1.0 4.8.2.0 \
4.9.0.0 4.9.1.0 4.10.0.0 4.10.1.0 4.11.0.0 4.11.1.0 \
4.12.0.0 4.13.0.0 4.14.0.0 4.14.1.0 4.14.2.0 4.14.3.0 \
4.15.0.0 4.16.0.0
# 3.0.3.1 3.0.3.2 ## not useful
tailVersions = $(call tail,$(versions))
# Prelude source files from hackage
preludes = $(patsubst %,Prelude/%.hs,$(versions))
# Only identifiers left over
onlyids = $(patsubst %,only-idents/%.txt,$(versions))
# Flattened to identifier lists
wordlists = $(patsubst %,word-lists/%.txt,$(versions))
# Difference to previous version
adds = $(patsubst %,added/%.txt,$(tailVersions))
# Commands
# onVersionPairs f = zipWith f versions (tail versions)
onVersionPairs = $(call zipWith,$1,$(versions),$(tailVersions))
# difference between word lists (only stuff that was added)
difference=$(shell comm -13 word-lists/$1.txt word-lists/$2.txt > added/$2.txt)
# Goals
.PHONY: default
default: all
.PHONY: all
all: $(dirs) fetch strip flatten diff Prelude-additions.md
$(dirs) : % :
mkdir -p $@
# Getting Prelude source files from hackage
.PHONY: fetch
fetch: Prelude $(preludes)
$(preludes) : Prelude/%.hs :
wget -O $@ https://hackage.haskell.org/package/base-$*/src/Prelude.hs
# Stripping comments and imports and syntax
.PHONY: strip
strip: only-idents $(onlyids)
# remove
# - block comments
# - line comments
# - preprocessor directives
# - 'import' lines
# - fixity directives
# - type signatures
# - keywords and other garbage: 'module' 'Prelude' 'where' 'let 'in' 'vx'
# - punctuation: ( , ) = ` ..
# - single letter variables and underscores
# - qualification
$(onlyids) : only-idents/%.txt : Prelude/%.hs Makefile
gsed -e '/{-.*-}/d; /{-/,/-}/d; s/--.*//g; /^#/d; /^import/d; /^infix/d; /::/d; s/\<module\>//g; s/\<Prelude\>//g; s/\<where\>//g; s/\<let\>//g; s/\<in\>//g; s/\<vx\>//g; s/(/ /g; s/)/ /g; s/,/ /g; s/=/ /g; s/`/ /g; s/\.\./ /g; s/\<[a-z_]\>//g; s/[A-Z][a-zA-Z]*\.//g;' $< > $@
# Flatten and sort to identifier list
.PHONY: flatten
flatten: word-lists $(wordlists)
# - replace spaces by new lines
# - trim
# - sort
# - remove duplicates, !
$(wordlists) : word-lists/%.txt : only-idents/%.txt # Makefile
tr " " "\n" < $< | gsed -e 's/\s+//g; /^\!$$/d;' | sort | uniq > $@
# Difference between word lists
.PHONY: diff
diff: added $(adds) # Makefile
# added/%.txt : word-lists/%.txt
$(adds) : $(wordlists) # Makefile
$(call onVersionPairs,difference)
# Generate report
# - for each base version, report identifiers added over previous version
# - omit empty lines
Prelude-additions.md : $(adds) Makefile
echo "# Additions to Haskell's \`Prelude\` since \`base-4.0.0.0\`\n" > $@
echo "| \`base\` version | additions |" >> $@
echo "|---|---|" >> $@
# for ver in $(tailVersions); do if [ -s "added/$$ver.txt" ]; then cat "added/$$ver.txt" | xargs echo -n "| $$ver | " >> $@ ; echo " |" >> $@; fi; done
for ver in $(tailVersions); do if [ -s "added/$$ver.txt" ]; then echo "| $$ver | \c" >> $@ ; for id in $$(cat "added/$$ver.txt"); do echo "\`$$id\` \c" >> $@; done; echo "|" >> $@; fi; done
# Note: \c suppresses final newline in echo
# Debugging
.PHONY: debug
debug:
@echo "versions = $(versions)"
@echo "preludes = $(preludes)"
@echo "adds = $(adds)"
# EOF
@andreasabel
Copy link
Author

The outcome is embarrassing little. Instead of programming the Makefile for 2.5 hours, I could have spent 10 minutes to extract the information from https://hackage.haskell.org/package/base-4.16.0.0/changelog.
But as people say: Three months in the lab save you one hour in the library.

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