MicroHs v0.15.0.0

There is a new version of MicroHs on GitHub.
There are lots of little changes, and more packages on Hackage now compile.

Release notes:

Features

  • New language extensions
    • EmptyDataDeriving
    • NondecreasingIndentation
    • MonoLocalBinds removed
    • MonomorphismRestriction
  • Evaluation stats in interactive system: set +s
  • STM (implementation from David Sabel)
  • GHC compatible exception handling (mask etc.)
  • System.Mem.Weak
  • Foreign.StablePtr
  • out.comb can be generated compressed and base64 encoded
  • Improved Data.ByteString
  • FFI wrapper for eval.c
  • New BFILE stuff: file descriptor, buffering, base64 coding
  • Double and Float are now different types
  • Int64/Word64 on 32 bit platforms
  • Instruction counts on supported platforms (MacOS&M4, Linux&x86_64)
  • Proper array package
  • Unboxed tuple and sum syntax accepted (but no unboxing)
  • Deriving Data, Foldable, Functor, Ix, Read, Traversable

Performance

  • Evaluation in the interactive system is much faster

FFI

  • foreign export ccall implemented
  • foreign import javascript implemented
  • JavaScript version of the MicroHs runtime is part of the distribution: generated/mhseval.js

Bug fixes

  • Lots

Packages

Contributors

43 Likes

Very impressive, I’m just wondering
You’ve implemented so many features that I almost wonder wich things are not yet supported?
How much does performance compare with GHC?
Is it better designed than GHC? Easier to modify, less complicated? Does it use the same pipeline?

2 Likes

I thought MonoLocalBinds were a requirement for GADTs!

There are some things missing from MicroHs:

  • Type families; needed for many things, e.g., generics. I plan to implement it.
  • Template Haskell. Nope, won’t happen
  • Quantified constraints. Yes, coming.
  • Implicit parameters. Nope.

Is it better designed than GHC? I don’t know.

Is it easier to modify? I think so, but that’s for others to answer.

Does it use the same pipeline? It’s a compiler, so some things are similar, some are different.

4 Likes

The worst that can happen without MonoLocalBinds is that you get an unexpected type error and have to add a type signature.

I would have liked to keep MonoLocalBinds, but a lot of packages rely on local bindings to be generalized. Given how reluctant some package maintainers are to accept my changes, I’ve given in.

2 Likes

By pipeline I mean parser, renamer, type checker, core, stg, cmm…

Here’s the pipeline

  • lexer, a state machine delivering tokens
  • parser, using classical parser combinators
  • typechecking
    • inserts dictionaries
    • desugers a little, e.g., do-notation
    • output is the same AST data type as input
    • several passes
      • kind check all types
      • generate deriving instances
      • turn classes and instances into regular definitions
      • typecheck values
  • desugaring
    • remove list comprehension
    • turn complex pattern matching into simple pattern matching
    • encode constructors/case to lambda expressions
    • some minor optimizations
      • remove let-bindings used 0 or 1 time
      • introduce local recursive functions
    • output language is lambda calculus + literals, just 4 constructors
      • variables
      • application
      • lambda
      • literals, i.e., numbers, bytestrings, primitive functions, FFI functions
  • bracket abstraction, i.e., get rid of lambdas by using combinators
  • serialize output

Done. The type checker is by far the most complex piece.

Edit: There is no separate renaming pass. I think having that is a mistake.

11 Likes

Oh, interesting—as someone who enjoys compiler pipelines, tell me more!

1 Like

We made the same no renamer pass in our in-house language at work. Its a very mixed bag – we certainly can get away without it. (But in part because we’ve got a goofy namespacing hack instead of proper modules). Usually it feels good to avoid an extraneous pass, and it simplifies the code. On occasion we have to work around the lack of a renamer with pushing various resolution functionality either down into the parser layer or up into the typechecking and evaluator layers, and sometimes all three, and subtle bugs can be introduced at which point I start cursing about “if only we weren’t too lazy to write a renamer”.

3 Likes