4

I came across the following code in GHC.Prim:

...

negateFloat# :: Float# -> Float#
negateFloat# = let x = x in x

-- |Truncates a @Float#@ value to the nearest @Int#@.
--     Results are undefined if the truncation if truncation yields
--     a value outside the range of @Int#@.

float2Int# :: Float# -> Int#
float2Int# = let x = x in x

expFloat# :: Float# -> Float#
expFloat# = let x = x in x

logFloat# :: Float# -> Float#
logFloat# = let x = x in x

...

In particular:

  1. float2Int# shouldn't even type check
  2. None of the functions take an argument and hence seem to be malformed
  3. None of the functions apply the mathematical operation they claim to
  4. All of the functions are "infinitely recursive": let x = x

I know the extension is called "MagicHash", but it can't be that magical. What gives?

(I guess I should add the disclaimer that I have no idea what -XMagicHash actually does, I just assumed it allowed the # syntax, and nothing more.)

crockeea
  • 21,651
  • 10
  • 48
  • 101

1 Answers1

14

The clue is at the top of the module:

{-
This is a generated file (generated by genprimopcode).
It is not code to actually be used. Its only purpose is to be
consumed by haddock.
-}

Incidentally, let x = x in x is equivalent to undefined, and is valid for any data type; x isn't constrained by being defined in any way other than self-referentially, so can be any type.

These functions are "primitive" meaning operations so basic they're not defined in Haskell code, and quite possibly just translated directly to machine instructions.

not my job
  • 642
  • 10
  • 21
  • So I've found code that *uses* this function, in a seemingly reasonable way [meta-repa](https://github.com/jankner/meta-repa/blob/master/FOASTyped.hs). I can't be *just* for documentation, can it? Is there another version of these functions defined elsewhere? – crockeea Feb 13 '14 at 23:04
  • @Eric Oh yes, but not here. They're primitive, meaning defined other than by Haskell code. – not my job Feb 13 '14 at 23:05
  • @Eric: That code uses the GHC built-ins. – Xeo Feb 13 '14 at 23:05
  • Point taken about my questions #1, #2, and #4. That's obvious in hindsight. – crockeea Feb 13 '14 at 23:05
  • In effect it's inlined as your code is compiled / imported into the runtume / written in a lower level language. – not my job Feb 13 '14 at 23:07
  • So is there any place I can see where it is actually defined? I don't expect any surprises, but it seems like I should be able to look if I want. – crockeea Feb 13 '14 at 23:07
  • Is there any reason for using `let x = x in x` over `undefined`? The latter is shorter and makes it more immediately clear that nothing is happening. – crockeea Feb 13 '14 at 23:09
  • 2
    `undefined` is defined in the prelude, which imports the primitives, not the other way round. Actually, `undefined` throws an error. `undefined = error "Prelude.undefined"` and `error s = throw (ErrorCall s)`, whereas `let x = x in x` is just a loop. – not my job Feb 13 '14 at 23:13
  • So Prelude is not in scope in GHC.Exts? – crockeea Feb 13 '14 at 23:15
  • Er... dunno, but I'm sure it's not in scope in `GHC.Prim`, which is the module linked to. – not my job Feb 13 '14 at 23:17
  • Oops, didn't realize it linked me to a different module! Thanks! – crockeea Feb 13 '14 at 23:18
  • 1
    The primitive operations don't exist in Haskell, but they do exist in cmm (C minus minus) : https://ghc.haskell.org/trac/ghc/browser/ghc/rts/PrimOps.cmm. – user2407038 Feb 14 '14 at 01:12