Well, I was doing a problem in which function I was using had a rigid variable. I had an idea of using arrays for that problem. So I thought of using arrays with same rigid vari
You're having trouble because the "inner" type signatures you've written out don't mean quite what they look like they'd mean. In particular, your uses of c
do not correspond with one another not the a
in the top signature and they must. Haskell is complaining that these "rigidly defined" type variables, despite being variables, cannot be the same, but since they're based on a "rigid" choice of what a
is... they must!
You can make GHC (but not Haskell in general) behave the way you'd like with an extension called {-# LANGUAGE ScopedTypeVariables #-}
where your code becomes
{-# LANGUAGE ScopedTypeVariables #-}
rearrange :: forall a . [Int] -> [a] -> [a]
rearrange l la = elems (f 1 posarr)
where
b = length l
listarr :: Array Int Int
listarr = listArray (1, b) l
arra :: Array Int a
arra = listArray (1,b) la
posarr :: Array Int a
posarr listArray (1,b) la
f i posarr
| (b < i) = posarr
| otherwise = f (i+1) (posarr // [(listarr!i,arra!i)])
Note that all I did was add the explicit forall
and changed some c
variables to a
. What ScopedTypeVariables
let you do is introduce type variable scopes using forall
where any type signatures in code that is indented below such an explicitly forall
'd signature can re-use the type variable names introduced in that forall
and have them correspond exactly.
Which might make more sense under examining how Haskell interprets type signatures without the extension. In particular, there is an implicit forall
before every type signature
-- is actually
foo :: [a] -> [a] -> [a] foo :: forall a. [a] -> [a] -> [a]
foo xs ys = it where foo xs ys = it where
it :: [a] it :: forall a. [a]
it = xs ++ ys it = xs ++ ys
Which forces the a
variable in each of these type signatures to be different and thus this fragment of code cannot compile because it is only valid if those two a
s are the same. With ScopedTypeVariables
we have
foo :: forall a . [a] -> [a] -> [a]
foo xs ys = it where
it :: [a]
it = xs ++ ys
where the inner signature's a
is scoped to mean exactly the same a
as in outer signature's.
J. Abrahamson explained how to fix the errors at hand, but note that this is way overcomplicated. You can just omit all the local type signatures1, the compiler is able to infer those by itself. (There sure enough are applications where you need local type signatures, or where it's helpful for readability; then you often need ScopedTypeVariables
. But not for such a simple function, IMO.)
Speaking of unnecessary complexity — there is no benefit whatsoever in explicitly index-iterating through an array you've just created with listArray
: it's pretty much equivalent (but much unwieldier) to just recursively destructing the list. And that can be written as a fold. Or, in cases like this where you iterate through two lists "in parallel", to folding on the zip
of those lists. In fact you don't need even the fold: there's a good reason that (//)
accepts a list of index-value pairs rather than just a single pair – because you'll normally want to update multiple elements2 in batch.
That simplifies your function drastically:
rearrange l la = elems $ posarr // zip l la
where posarr = listArray (1, length l) la
1So I'm not misunderstood: I really mean only local type signatures. On the top-level, everything should have a signature except perhaps completely trivial stuff that's only used inside your module (but then it's in a way also a local signature).
2There is more to this than just convenience: your solution is actually very inefficient, because at each modification step a copy of the entire array needs to be made, so you can safely access the intermediate results in the purely functional language. Calling //
with multiple pairs right away omits this: since the intermediate steps are never exposed, GHC can do magic under the hood, do destructive updates like you could in an imperative language (or in Haskell with the ST
monad). Which is much faster.