Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell: Type declaration in `where`

Tags:

types

haskell

I have an example of function, in which I can't write a type in where clause. replace is a function, that replaces all Xs by Ys in a given list.

replace :: (Eq a) => a -> a -> [a] -> [a]
replace x y xs = map helper xs
  where
    helper :: (Eq a) => a -> a
    helper = (\el -> if el == x then y else el)

When I try to compile this function I get an error:

ProblemsArithmetics.hs:156:31:
Could not deduce (a ~ a1)
from the context (Eq a)
  bound by the type signature for
             replace :: Eq a => a -> a -> [a] -> [a]
  at ProblemsArithmetics.hs:152:12-41
or from (Eq a1)
  bound by the type signature for helper :: Eq a1 => a1 -> a1
  at ProblemsArithmetics.hs:155:15-30
  ‘a’ is a rigid type variable bound by
      the type signature for replace :: Eq a => a -> a -> [a] -> [a]
      at ProblemsArithmetics.hs:152:12
  ‘a1’ is a rigid type variable bound by
       the type signature for helper :: Eq a1 => a1 -> a1
       at ProblemsArithmetics.hs:155:15
Relevant bindings include
  el :: a1 (bound at ProblemsArithmetics.hs:156:16)
  helper :: a1 -> a1 (bound at ProblemsArithmetics.hs:156:5)
  xs :: [a] (bound at ProblemsArithmetics.hs:153:13)
  y :: a (bound at ProblemsArithmetics.hs:153:11)
  x :: a (bound at ProblemsArithmetics.hs:153:9)
  replace :: a -> a -> [a] -> [a]
    (bound at ProblemsArithmetics.hs:153:1)
In the second argument of ‘(==)’, namely ‘x’
In the expression: el == x

At the same time, if I omit

helper :: (Eq a) => a -> a

the code is compiled fine.

While I understand the logic behind it (a in replace type declaration and a in helper type declaration are different as), and there are at least 2 workarounds (omit type declaration or pass x and y as parameters to helper function), my question is:

Is there any way to tell the compiler that I mean the same type in both type declarations?

like image 544
Mariya Davydova Avatar asked Mar 26 '15 09:03

Mariya Davydova


1 Answers

If you enable ScopedTypeVariables and introduce a type variable with a forall, then it becomes visible in the inner scope.

{-# LANGUAGE ScopedTypeVariables #-}

replace :: forall a. (Eq a) => a -> a -> [a] -> [a]
replace x y xs = map helper xs
  where
    helper :: a -> a
    helper = (\el -> if el == x then y else el)
like image 156
András Kovács Avatar answered Oct 08 '22 08:10

András Kovács