Skip to content

GHC Language Options vs. Frege

Ingo60 edited this page Dec 29, 2014 · 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 or in type signatures, that is, in the context of a ::. The consequence is that the following is a syntax error:

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

but the equivalent in record notation is ok

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

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 actually moves closed let bindings to the top level, so they're type checked separatly and most likely before the definition that contains the let bindings. The remaining 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.

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