Specifying a function type signature in a where clause

swift generic function where clause
reference to generic type requires arguments in
swift function type
method signature java
swift pass type as parameter
generic parameter is not used in function signature
swift generic return type
swift pass generic type as parameter

The following function implements the good old filter function from lists by using the recursion-schemes library.

import Data.Functor.Foldable 

catafilter :: (a -> Bool) -> [a] -> [a] 
catafilter p = cata alg 
  where
    -- alg :: ListF a [a] -> [a]
    alg  Nil  =  []
    alg  (Cons x xs) = if (p x) then x : xs else xs

It compiles and a short test like catafilter odd [1,2,3,4] is successful. However, if I uncomment the type signature for alg I get the following error:

src/cata.hs:8:30: error:
    • Couldn't match expected type ‘a’ with actual type ‘a1’
      ‘a1’ is a rigid type variable bound by
        the type signature for:
          alg :: forall a1. ListF a1 [a1] -> [a1]
        at src/cata.hs:6:5-29
      ‘a’ is a rigid type variable bound by
        the type signature for:
          catafilter :: forall a. (a -> Bool) -> [a] -> [a]
        at src/cata.hs:3:1-39
    • In the first argument of ‘p’, namely ‘x’
      In the expression: (p x)
      In the expression: if (p x) then x : xs else xs
    • Relevant bindings include
        xs :: [a1] (bound at src/cata.hs:8:18)
        x :: a1 (bound at src/cata.hs:8:16)
        alg :: ListF a1 [a1] -> [a1] (bound at src/cata.hs:7:5)
        p :: a -> Bool (bound at src/cata.hs:4:12)
        catafilter :: (a -> Bool) -> [a] -> [a] (bound at src/cata.hs:4:1)
  |
8 |     alg  (Cons x xs) = if (p x) then x : xs else xs
  |                              ^

The answer to the SO question type-signature-in-a-where-clause suggests to use the ScopedTypeVariables extension. The comment in the last answer to why-is-it-so-uncommon-to-use-type-signatures-in-where-clauses suggests to use a forall quantification.

So I added:

{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE RankNTypes #-}

at the top of my module and tried different type signatures for alg like: alg :: forall a. ListF a [a] -> [a] or alg :: forall b. ListF b [b] -> [b] or adding a forall to the catalist type signature. Nothing compiled!

Question: Why I'm not able to specify a type signature for alg?

Generic Parameters and Arguments, A generic parameter clause specifies the type parameters of a generic type or rest of the type, function, or initializer declaration, including in the signature of  The answer to the SO question type-signature-in-a-where-clause suggests to use the ScopedTypeVariables extension. The comment in the last answer to why-is-it-so-uncommon-to-use-type-signatures-in-where-clauses suggests to use a forall quantification.

This works

{-# Language ScopedTypeVariables #-}

import Data.Functor.Foldable 

catafilter :: forall a. (a -> Bool) -> [a] -> [a] 
catafilter p = cata alg
  where
    alg :: ListF a [a] -> [a]
    alg  Nil  =  []
    alg  (Cons x xs) = if (p x) then x : xs else xs

If you omit the forall, these are completely different as (even though syntactically they are the same).

Because of implicit quantification, your uncommented version is taken to be

catafilter :: forall a. (a -> Bool) -> [a] -> [a] 
catafilter p = cata alg
  where
    alg :: forall a1. ListF a1 [a1] -> [a1]
    alg  Nil  =  []
    alg  (Cons x xs) = if (p x) then x : xs else xs

This explains your error message:

Couldn't match expected type ‘a’ with actual type ‘a1’

The predicate (p :: a -> Bool) expects an argument of type a but it was given x :: a1 from Cons x xs :: ListF a1 [a1]!

See if the explicitly quantified version makes sense given the bindings from the error message:

xs         :: [a1] 
x          :: a1
alg        :: ListF a1 [a1] -> [a1] 
p          :: a -> Bool 
catafilter :: (a -> Bool) -> [a] -> [a]

where (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,  Specifying a function type signature in a where clause Hot Network Questions “Depend on abstractions, not on concretions” what is the exact meaning of this term

This works, and avoids all that counter-intuitive mucking around with foralls

{-# LANGUAGE ScopedTypeVariables #-}

import Data.Functor.Foldable 

catafilter :: (a -> Bool) -> [a] -> [a] 
catafilter p = cata alg 
  where
    -- alg :: ListF a [a] -> [a]
    alg  (Nil :: ListF aa [aa])  =  [] :: [aa]
    alg  (Cons x xs) = if (p x) then x : xs else xs

On the alg Nil equation I could actually use tyvar a: I used aa merely to show they're distinct bindings. Because aa appears on a pattern, the compiler unifies it with a from the signature for catafilter.

You could also/instead put the type annotations on the alg Cons equation.

I understand @Jogger's confusion as to why ghc is so fussy about the position of the forall; and the nervousness that a forall perhaps indicates RankNTypes.

Type signature, In computer science, a type signature or type annotation defines the inputs and outputs for a function, It specifies the general information about a function like the name, scope and parameters. Privacy policy · About Wikipedia · Disclaimers · Contact Wikipedia · Developers · Statistics · Cookie statement · Mobile view. As you know, F# uses type inference to deduce types, so you don’t often need to explicitly specify types in your code, especially for functions. But in order to work effectively in F#, you do need to understand the type syntax, so that you can build your own types, debug type errors, and understand function signatures.

The problem is that alg depends on an external p, so alg's type can't be simply polymorphic.

One simple way around it is to make it independent of any external entities by passing them in as the function arguments, so that the function can have its simply polymorphic type as expected:

catafilter :: (a -> Bool) -> [a] -> [a]
catafilter = cata . alg
  where
    alg :: (b -> Bool) -> ListF b [b] -> [b]
    alg p Nil  =  []
    alg p (Cons x xs)  =  if (p x) then x : xs else xs

This doesn't need any language extensions.

[Haskell-beginners] type signature error in a where clause, November 2012, 22:04:15, Mark Wallace wrote: >> >>> I'm writing a merge sort function, but I get type error under such >>> implementation:  The where clause can specify that the type is a class or a struct. The struct constraint removes the need to specify a base class constraint of System.ValueType. The System.ValueType type may not be used as a base class constraint.

[PDF] Haskell Cheat Sheet, a syntax error to give a variable or a function one of these names. The if statement has this “signature”: used here to specify which functions, types, con-​. Program execution continues with the statement following the statement that called the Function procedure. Any number of Exit Function statements can appear anywhere in a Function procedure. Like a Sub procedure, a Function procedure is a separate procedure that can take arguments, perform a series of statements,

Beginning Rust: From Novice to Professional, The first statement is a declaration of a “trait” named "HasSquareRoot", A Rust trait is a container of function signatures; in this case it contains just one signature​. or API, is implemented here for the specified types by the specified code. The requirements in a generic where clause specify that a type parameter inherits from a class or conforms to a protocol or protocol composition. Although the generic where clause provides syntactic sugar for expressing simple constraints on type parameters (for example, <T: Comparable> is equivalent to <T>

Mastering Rust: Learn about memory safety, type system, , This is the most common syntax to specify trait bounds on generic items. We read the preceding function as follows show_me is a method that takes any type Using where clauses: This syntax is used when the type signature of any generic​  A function invocation (or call) is an expression, whose data type is that of the function. Before invoking a function, you must declare and define it. You can either declare it first (with function_declaration ) and then define it later in the same block, subprogram, or package (with function_definition ) or declare and define it at the same

Comments
  • Try replacing p x with undefined. Does the error go away? Why/why not? — Pass the predicate explicitly to alg :: forall a1. (a1 -> Bool) -> ListF a1 [a1] -> [a1] with catafilter = cata . alg. Which foralls can you remove? Can you freely rename your type variables or not?
  • Thanks for your additional answer! For me it was important to have a normal type signature of the function alg as a compiler checkable signature and not only as a comment. A comment may be wrong. And thanks to the answers of chi and Icland_jack I now understand forall
  • I left the comment in from your O.P. It is the two type annotations that are doing the work, and they are checked by the compiler.