Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I give expressions generic types in a "where" clause?

(please excuse the horribly contrived example)

What I want to do is specify types in the where-clause:

somemap :: (a -> b) -> [a] -> [b]
somemap f xs = ys
  where
    some = take 5 xs :: [a]
    ys = map f some :: [b]

But this causes an error:

*Main> :load file.hs 
[1 of 1] Compiling Main             ( file.hs, interpreted )

fil.hs:15:18:
    Couldn't match expected type `a1' against inferred type `a'
      `a1' is a rigid type variable bound by
           an expression type signature at file.hs:15:25
      `a' is a rigid type variable bound by
          the type signature for `somemap' at file.hs:12:12
      Expected type: [a1]
      Inferred type: [a]
    In the second argument of `take', namely `xs'
    In the expression: take 5 xs :: [a]

file.hs:16:13:
    Couldn't match expected type `b1' against inferred type `b'
      `b1' is a rigid type variable bound by
           an expression type signature at file.hs:16:24
      `b' is a rigid type variable bound by
          the type signature for `somemap' at file.hs:12:17
    In the first argument of `map', namely `f'
    In the expression: map f some :: [b]
    In the definition of `ys': ys = map f some :: [b]
Failed, modules loaded: none.

Whereas if I just specify concrete types, substituting Int for a and Bool for b, no problem:

somemap :: (Int -> Bool) -> [Int] -> [Bool]
somemap f xs = ys
  where
    some = take 5 xs :: [Int]
    ys = map f some :: [Bool]

So my question is: How do I specify generic types and type constraints in a where-clause?

like image 659
Matt Fenwick Avatar asked May 03 '12 15:05

Matt Fenwick


People also ask

Which syntax is used to declare generic?

Syntax Declaration of Generic Interface The general syntax to declare a generic interface is as follows: interface interface-name<T> { void method-name(T t); // public abstract method. } In the above syntax, <T> is called a generic type parameter that specifies any data type used in the interface.

Where is generic type constraint?

The where clause in a generic definition specifies constraints on the types that are used as arguments for type parameters in a generic type, method, delegate, or local function. Constraints can specify interfaces, base classes, or require a generic type to be a reference, value, or unmanaged type.

What is generic interface?

A generic interface is primarily a normal interface like any other. It can be used to declare a variable but assigned the appropriate class. It can be returned from a method. It can be passed as argument. You pass a generic interface primarily the same way you would an interface.


1 Answers

Inside the where clause, the type variables a and b are new type variables; type variables aren't scoped, so every type signature has a new supply of them, just as if they were defined at the top level.

If you turn on the ScopedTypeVariables extension (put {-# LANGUAGE ScopedTypeVariables #-} at the top of your file), and change somemap's type declaration to:

somemap :: forall a b. (a -> b) -> [a] -> [b]

then the where clause definitions you specified will work correctly. I think the foralls are only required for backwards compatibility, so that code that reuses type variables in where clauses for polymorphic values doesn't break.

If you don't want to use an extension, the alternative is to define ugly helper functions to unify the types, like asTypeOf.

like image 73
ehird Avatar answered Oct 05 '22 22:10

ehird