1

The code below compiles just fine:

ecbEncryptRandomly :: RandomGen g => ByteString -> g -> (ByteString, g)
ecbEncryptRandomly bs gen = let key :: AES
                                (key, newGen) = random gen
                            in  (ecbEncrypt key bs, newGen)

Now, I like things to be pretty, so I figured I'd just provide a type annotation for the entire tuple in my let:

ecbEncryptRandomly :: RandomGen g => ByteString -> g -> (ByteString, g)
ecbEncryptRandomly bs gen = let (key, newGen) = random gen :: (AES, g)
                            in  (ecbEncrypt key bs, newGen)

GHC doesn't like this one bit, and spits out the following error:

ECBCBCoracle.hs:32:56:
Could not deduce (g ~ g1)
from the context (RandomGen g)
  bound by the type signature for
             ecbEncryptRandomly :: RandomGen g =>
                                   ByteString -> g -> (ByteString, g)
  at ECBCBCoracle.hs:31:23-71
  ‘g’ is a rigid type variable bound by
      the type signature for
        ecbEncryptRandomly :: RandomGen g =>
                              ByteString -> g -> (ByteString, g)
      at ECBCBCoracle.hs:31:23
  ‘g1’ is a rigid type variable bound by
       an expression type signature: (AES, g1) at ECBCBCoracle.hs:32:49
Relevant bindings include
  gen :: g (bound at ECBCBCoracle.hs:32:23)
  ecbEncryptRandomly :: ByteString -> g -> (ByteString, g)
    (bound at ECBCBCoracle.hs:32:1)
In the first argument of ‘random’, namely ‘gen’
In the expression: random gen :: (AES, g)

For some reason GHC seems to want to make the g in the tuple a new type? The most perplexing thing about this is that when I use a typed hole, it suggests that I adopt g as my type!

In other words, the following code:

ecbEncryptRandomly :: RandomGen g => ByteString -> g -> (ByteString, g)
ecbEncryptRandomly bs gen = let key :: AES
                                (key, _) = random gen
                            in  (ecbEncrypt key bs, _)

Generates the following error:

ECBCBCoracle.hs:34:53:
Found hole ‘_’ with type: g
Where: ‘g’ is a rigid type variable bound by
           the type signature for
             ecbEncryptRandomly :: RandomGen g =>
                                   ByteString -> g -> (ByteString, g)
           at ECBCBCoracle.hs:31:23
Relevant bindings include
  key :: AES (bound at ECBCBCoracle.hs:33:34)
  gen :: g (bound at ECBCBCoracle.hs:32:23)
  bs :: ByteString (bound at ECBCBCoracle.hs:32:20)
  ecbEncryptRandomly :: ByteString -> g -> (ByteString, g)
    (bound at ECBCBCoracle.hs:32:1)
In the expression: _
In the expression: (ecbEncrypt key bs, _)
In the expression:
  let
    key :: AES
    (key, _) = random gen
  in (ecbEncrypt key bs, _)

What's going on?

Matthew Leon
  • 123
  • 3
  • You can't use the type `g` in a function body to refer to a type in the function signature, without ScopedTypeVariables or something like it. Your problematic expression creates a brand-new `g` with no relation to the one in the function signature. – amalloy Aug 20 '14 at 02:17
  • See [this answre](http://stackoverflow.com/a/25369364/839246) I wrote just yesterday on this same problem. If you're happy with that answer I'd like to close this as a duplicate so that we don't have the same question answered a bunch of different times on here (I like to ask before using my close powers). – bheklilr Aug 20 '14 at 02:51
  • After a quick search it seems that [this](http://stackoverflow.com/questions/8400150/how-to-relate-to-type-from-outer-context/8400414#8400414) question would make for a more appropriate duplicate as it's been around longer, so I'd use it if I closed. – bheklilr Aug 20 '14 at 02:55

1 Answers1

5

I think you need the ScopedTypeVariables extension so that the g values are actually the same g and not separate.

Axman6
  • 909
  • 5
  • 16