Skip to content

GHC Language Options vs. Frege

Ingo Wechsung edited this page Oct 14, 2015 · 7 revisions

This document discusses GHC language options that correspond to Frege features.

Summary

Frege has features that correspond more or less roughly to the following GHC language options: -XUnicodeSyntax -XRebindableSyntax -XPostfixOperators -XNamedFieldPuns -XLiberalTypeSynonyms (restricted) -XStandaloneDeriving (different keyword) -XTypeSynonymInstances -XFlexibleInstances (restricted) -XInstanceSigs -XRankNTypes -XNoMonomorphismRestriction -XRelaxedPolyRec -XMonoLocalBindings -XBangPatterns

Read on to learn more details.

Details

The following unicode symbols are recognized and interpreted:

  • ← U+2190 LEFTWARDS ARROW is interpreted as <-
  • → U+2192 RIGHTWARDS ARROW is interpreted as ->
  • ⇒ U+21D2 RIGHTWARDS DOUBLE ARROW is interpreted as =>
  • ∀ U+2200 FOR ALL is interpreted as keyword forall
  • ∷ U+2237 PROPORTION is interpreted as ::
  • … U+2026 HORIZONTAL ELLIPSIS is interpreted as ..

The interpretation takes place only if the symbol stands alone and is not part of some operator, i.e.

a ←| b

is not the same as

a <-| b

Frege module names map to class names of the underlying platform (i.e. JVM). Thus, they are hierarchical by nature.

Because classes with simple names cannot get imported from classes with qualified names due to restrictions of the JVM, the prelude module is named frege.Prelude.

Pattern guards are part of Haskell 2010 and as such are no GHC extension anymore, though they are still listed on the linked page. They're fully supported in Frege.

Negation, e.g. -(f x), means negate (f x) and whatever negate is in scope will be used.

do notation is translated using whatever functions (>>=), (>>) and fail are in scope.

Right operator sections, e.g. (`op` v) are translated to flip (op) (v) using whatever flip function is in scope.

Left operator sections, e.g. (v `op`) are translated to (op) (v). Unlike with GHC, this is also allowed on the left hand side of function definitions:

infix 1 `³`  -- make ³ an operator (associativity and precedence immaterial)
(x³) =  x^3  -- legal

Remember that applications of such a postfix operator must always occur in the form of a section or in prefix form, as the operator is syntactically still treated as a binary one.

Record puns are supported in patterns, record constructor applications and record update expressions.

The right hand side of a type definition can be a forall type:

type Discard a = forall b. Show b => a -> b -> (a, String)

Currently, a type synonym may not be applied to a forall type. A type synonym must not occur partially applied.

This is actually the only way to derive an instance in Frege. The keyword is derive.

Instance heads may use type synonyms. So the following is legal.

type Point a = (a,a)
instance C (Point a) where ...

In addition, concrete types may be given instead of type variables. For example:

instance C (Maybe Int) where ...

However, for every class C and type constructor T there must be still at most one C instance for applications of T. For example, we may not subsequently define

instance C (Maybe Double) where ... -- wrong because of C (Maybe Int) 

This is allowed in Frege, and the supplied signatures get checked for correctness.

Explicit forall types can occur on the right hand side of a type definition, in type signatures (that is, following a ::) or as arguments of constructor definitions. For example:

data T = T (forall x.x->x)   

which is equivalent to the record notation:

data F = F  {fun :: forall x.x->x} 

as well as

type I = forall x. x->x
data T = T I

In Frege, we don't have the monomorphism restriction.

For top level bindings, this seems to work exactly like described in the GHC manual. For let bindings, see below.

The Frege compiler does not generalise let bound bindings at all. (This is a bit more radical and also simpler than what Haskell does).

The let bound bindings either do have a type signature, in which case they're left alone, or they don't, and the types of those latter ones are not generalised, but remain monomorphic.

In addition, bindings that have a signature and don't reference other local items are moved to the top level. Bindings that are used just once are inlined, unless they're recursive.

Unlike in GHC, a pattern with a bang at the outermost level is allowed at the top level of a module. At runtime, this has the effect that the value is computed (to WHNF) as soon as the class that results from compilation of the module is initialized. The rationale is that especially for numeric constants, one does not want to have an indirection introduced through a thunk.

Clone this wiki locally