iTranslated by AI
What's New in GHC 9.6
GHC 9.6.1 was released on March 12, 2023.
In this article, we will review the new features of GHC 9.6. Previous similar articles are:
- New features in GHC 9.2 and GHC trends in 2021
- New features in GHC 8.10 and GHC 9.0
- New features in GHC 9.4
This article is not intended to be an exhaustive introduction. Please also refer to the official release notes and related documents:
- 2.1. Version 9.6.1 — Glasgow Haskell Compiler 9.6.1 User's Guide
- Changelog for base-4.18.0.0 | Hackage
- GHC 9.6.x Migration Guide
Features in GHC 9.6
JavaScript backend
- javascript backend · Wiki · Glasgow Haskell Compiler / GHC · GitLab
- JavaScript backend merged into GHC | IOG Engineering
A JavaScript backend has been added to GHC. This is effectively a merge of GHCJS.
At this stage, several features such as Template Haskell and foreign export appear to be missing. Let's look forward to future updates.
As of GHC 9.6, GHC is not yet capable of "switching targets via runtime options," so instead of a standard GHC, you will need a GHC built as a cross-compiler targeting JS. For build instructions, you can refer to:
As a side note, I have published the Dockerfile I wrote here:
WebAssembly backend
- WebAssembly backend · Wiki · Glasgow Haskell Compiler / GHC · GitLab
- WebAssembly goals · Wiki · Glasgow Haskell Compiler / GHC · GitLab
- WebAssembly backend merged into GHC - Tweag
A WebAssembly backend has been added to GHC. This is effectively a merge of Asterius.
While WebAssembly is often associated with the Web, it seems to be specifically for WASI at the GHC 9.6 stage. In the future, it should be possible to interact with JavaScript via foreign import/export javascript.
As of GHC 9.6, GHC is not yet capable of "switching targets via runtime options," so instead of a standard GHC, you will need a GHC built as a cross-compiler targeting wasm.
If you want to try it out yourself, the following link provides instructions for installing binaries via Nix or building it manually:
I also plan to prepare a Dockerfile. I have placed a Dockerfile for building GHC for wasm32-wasi in the repository mentioned above. It includes the build for LLVM as well as GHC, so please feel free to try it if you are interested. I have confirmed it works on an AArch64 machine.
GHC WebAssembly Weekly Updates are being posted on the Haskell Discourse:
Delimited continuation primitives
For more about delimited continuations, please see Prof. Asai's Introduction to shift/reset programming or my article Various Delimited Continuations | Notebook.
The following types and functions will be available in the GHC.Exts module:
type PromptTag# :: Type -> UnliftedType
newPromptTag# :: forall (a :: Type). State# RealWorld -> (# State# RealWorld, PromptTag# a #)
prompt#
:: forall (a :: Type)
. PromptTag# a
-> (State# RealWorld -> (# State# RealWorld, a #))
-> State# RealWorld -> (# State# RealWorld, a #)
control0#
:: forall (a :: Type) (r :: RuntimeRep) (b :: TYPE r)
. PromptTag# a
-> (((State# RealWorld -> (# State# RealWorld, b #))
-> State# RealWorld -> (# State# RealWorld, a #))
-> State# RealWorld -> (# State# RealWorld, a #))
-> State# RealWorld -> (# State# RealWorld, b #)
The types are a bit hard to follow, but if you read State# RealWorld -> (# State# RealWorld, a #) as IO a, it looks like this:
newPromptTag :: IO (PromptTag a)
prompt :: PromptTag a -> IO a -> IO a
control0 :: PromptTag a -> ((IO b -> IO a) -> IO a) -> IO b
However, because the interaction between delimited continuations and existing resource management like withFile is tricky, an IO-wrapped version is not provided in the standard library.
Since operating on delimited continuations is a side effect, you need to use some kind of monad to use them in Haskell. Therefore, you might find that porting continuation sample code from other languages feels a bit clunky.
An extensible effects library utilizing delimited continuation primitives seems to be under development (though the last update was in 2020, so it might be a bit outdated):
There's also an article about doing algebraic effects using delimited continuations:
Support for the Haskell Error Index
- The Haskell Error Index — Haskell Error Index
- Announcing the Haskell Error Index - Haskell Foundation - Haskell Community
An effort has begun to assign codes like [GHC-12345] to error messages in GHC and surrounding tools so that related information can be looked up online. As a result, error numbers will be included starting with GHC 9.6.
Apparently, this was inspired by a similar mechanism in Rust.
Type and Kind Definitions Without Data Constructors: The TypeData Extension
- Define Kinds Without Promotion
- Allow defining kinds alone, without a datatype (#6024) · Issues · Glasgow Haskell Compiler / GHC · GitLab
Using the DataKinds extension, you can promote types to kinds and data constructors to the type level. In some cases, you might use a data declaration just to define a custom kind and type without actually needing the data type itself.
With the TypeData extension, you can now define kinds and types without defining value-level types or data constructors. The syntax looks like this:
type data T = MkT
Example:
ghci> :set -XTypeData
ghci> type data T = MkT
ghci> :type MkT
<interactive>:1:1: error: [GHC-31891]
• Illegal term-level use of the type constructor or class ‘MkT’
• defined at <interactive>:2:15
• In the expression: MkT
ghci> :kind MkT
MkT :: T
Relaxed restrictions on label names for OverloadedLabels
Previously, an identifier had to follow the # symbol, but now you can write things like #3 or #"Foo".
ConstPtr type for CApiFFI
- #22043: CApiFFI does not account for const qualifier · Issues · Glasgow Haskell Compiler / GHC · GitLab
- Foreign.C.ConstPtr
Using the capi calling convention allows you to call things that look like functions but are not supported by the standard C FFI, such as C macros or variadic functions on AArch64 Darwin. This is achieved by GHC generating intermediate C code and having it compiled by a C compiler.
In this process, C type annotations are determined based on Haskell type annotations. However, there was an issue where the types wouldn't match because const-qualified pointers couldn't be described on the Haskell side.
To solve this problem, the ConstPtr type has been added to represent const-qualified pointers.
Providing an unambiguous name for the list type: the List type
- Non-punning list and tuple syntax
- Non-punning list and tuple syntax (-XListTuplePuns, -XNoListTuplePuns) (#21294) · Issues · Glasgow Haskell Compiler / GHC · GitLab
Traditionally, the Haskell list type has been denoted by []. Meanwhile, the same [] notation is also used for list terms (values).
Normally, this was fine because type notation and term notation did not mix. However, in future Haskell—Dependent Haskell—the distinction between terms and types is expected to become increasingly blurred.
There are already situations today where term and type notation overlap. This occurs with the DataKinds extension. Let's look at the following code:
ghci> :kind []
[] :: Type -> Type
ghci> :kind [Int]
[Int] :: Type
This is expected behavior; it simply displays the kind of the list type constructor and a specific list type.
However, what happens if we increase the number of "elements" to two or more?
ghci> :kind [Int,Int]
[Int,Int] :: [Type]
ghci> :kind [Int,Int,Int]
[Int,Int,Int] :: [Type]
ghci> :kind [Int,Int,Int,Int]
[Int,Int,Int,Int] :: [Type]
Surprisingly, this does not result in an error. This is interpreted as a type-level list—a promotion of the term-level [] to the type level.
Previously, representing an empty type-level list or a type-level list with a single element required prefixing it with ' to disambiguate:
ghci> :kind '[]
'[] :: [a]
ghci> :kind '[Int]
'[Int] :: [Type]
On the other hand, what happens when we want to mix types within term-level expressions? In future Haskell, it is anticipated that you will be able to pass types directly to function arguments without the @ symbol (as the language extension RequiredTypeArguments is planned for addition):
{-# LANGUAGE RequiredTypeArguments #-}
sizeOf :: forall a -> Sized a => Int
main = print (sizeOf Int)
Here, if you try to pass the type [Int] (a list of Int) as sizeOf [Int], the term syntax takes precedence, and a single-element type-level list ends up being passed as the argument!
While a notation like (type ...) is planned to be introduced to explicitly indicate the use of type-level names within terms (similar to how ' explicitly indicates term-level names in types), the problem could have been avoided entirely if the notations for the list type and the list literal were different in the first place.
Consequently, List is being introduced as a name that always represents the list type. You can think of it as the following definition being built-in:
module GHC.Exts where
-- In reality, it is not a standard type alias (you can define instances without TypeSynonymInstances/FlexibleInstances)
type List = []
Similar changes are planned for tuples, where names like Unit and Tuple<n> will be introduced to always represent tuple types. The one-element tuple Solo has also had its data constructor renamed to MkSolo.
Eventually, there are plans to introduce the NoListTuplePuns extension, where [] and () will no longer represent types at all.
For now, in GHC 9.6, the List type has been added, and Solo :: a -> Solo a has been renamed to MkSolo. Tuple names and NoListTuplePuns are expected to arrive a bit later.
Other library changes
-
liftA2of theApplicativeclass is now exported fromPrelude. -
Data.Char.isUpperCase/isLowerCase- Reportedly, their Unicode-related properties are slightly different from before.
- The
natSing,symbolSing, andcharSingmethods are now exported from theKnownfamily of type classes inGHC.TypeLitsandGHC.TypeNats. TheSNat,SSymbol, andSChartypes are also exported.- Expose
KnownSymbol's method andSSymbol· Issue #85 · haskell/core-libraries-committee - Export symbolSing, SSymbol, and friends (CLC#85) (!9064) · Merge requests · Glasgow Haskell Compiler / GHC · GitLab
- This change is related to enabling the use of
withDictwith these type classes.
- Expose
Build system becomes Hadrian-only
Previously, there were two ways to build GHC:
- Traditional make
- Hadrian, written in Haskell/Shake
However, in this release, the traditional make-based build system has been removed.
To build using Hadrian, you can use commands like the following:
$ ./boot # When building from source obtained via Git
$ ./configure
$ hadrian/build -j
For more details, please refer to hadrian/README.md or run hadrian/build --help.
Discussion