Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XTypeOperators extension doesn't work as pragma

Tags:

types

haskell

I'm using GHCi 7.0.3 with the following program that implements type-level list:

{-# LANGUAGE TypeOperators #-}

data True
data False

-- List
data Nil
data Cons x xs

-- Type-level infix operator must begin with ':'
data x ::: xs
infixr 5 ::: -- set precedence level to 5 (tight)

It compiles, but when I test it with:

:t (undefined :: True:::Nil)

(what's the type of undefined when cast to type True:::Nil?) I get this error:

Illegal operator `:::' in type `True ::: Nil'
  Use -XTypeOperators to allow operators in types

And indeed, when I start GHCi with the flag

-XTypeOperators

I get the expected result:

(undefined :: True ::: Nil) :: True ::: Nil

My question is: Why doesn't the equivalent pragma work:

{-# LANGUAGE TypeOperators #-}

Edit: If pragmas don't extend to GHCi environment than I have another puzzle. I tried this program:

class And b1 b2 b | b1 b2 -> b where
    andf :: b1 -> b2 -> b

-- truth table
instance And True True True where andf = undefined
instance And True False False where andf = undefined
instance And False True False where andf = undefined
instance And False False False where andf = undefined

It required the following pragmas:

{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}

But once compiled, I could use it in GHCi:

*Main> :t andf (undefined::True) (undefined::False)
          andf (undefined::True) (undefined::False) :: False

I guess in the list case the interpreter couldn't even parse the expression with type-level operator :::, whereas in the case of multiparameter classes the command line was parseable. But, come to think of it, GHCi performed type inference using multi-parameter classes and functional dependencies, didn't it? This type inference is done in GHCi, and not by calling some function in the compiled code, right?

like image 320
Bartosz Milewski Avatar asked Dec 26 '11 18:12

Bartosz Milewski


2 Answers

The other answers are correct about enabling the extension in GHCi, either from the GHCi prompt or as a flag when starting GHCi. There is a third option, however--you can create a .ghci file that will be loaded and run every time you start GHCi, and use that to enable the extension automatically. Particularly for things like TypeOperators, where there's very little harm in having it enabled, it's nicely convenient.

For example, here's what mine looks like right now:

:set prompt "∀x. x ⊢ "
:set -XTypeOperators
import Control.Monad
import Control.Applicative
import Control.Arrow

The .ghci file goes in whatever your system's standard location is for such files.


To answer your extended question: The code in question works in GHCi roughly because it would also work if used in another module, which imported the module using the pragmas but didn't enable them itself. GHC is more than capable of enabling extensions on a per-module basis, even when the exported definitions couldn't possibly make sense without an extension, or have inferred types that require it.

The distinction is a little fuzzy in GHCi because it also puts non-exported definitions from the module in scope, but in general anything that would work if used from another module will also work at the GHCi prompt.

like image 60
C. A. McCann Avatar answered Oct 01 '22 05:10

C. A. McCann


Your pragma is correct; the problem is that you're trying to use it from within GHCi, which doesn't inherit the extensions of the loaded module,1 but does pass the options it's given to GHC to compile the files you list (which is why it has the same effect as the pragma).

You should keep the pragma, and either pass -XTypeOperators when you start GHCi, or enable it after loading the file as follows:

GHCi> :set -XTypeOperators

1 Which could be very undesirable, and probably impossible in many cases, for e.g. loading compiled modules.

like image 28
ehird Avatar answered Oct 01 '22 04:10

ehird