Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The type of foldr (.) id

Tags:

haskell

I'm trying to figure out the type of the expression :

foldr (.) id 

GHCI gives me :

foldr (.) id :: Foldable t => t (b -> b) -> b -> b

And I can't figure this out. foldr type is Foldable t => (a -> b -> b) -> b -> t a -> b. So it takes 3 parameters as input. So i thought that foldr (.) id should take a single parameter as input. Can someone explain how to analyze the type of this expresion ?

like image 622
Tomer Avatar asked Feb 25 '20 16:02

Tomer


People also ask

What is the type of foldr function?

The foldr function, pronounced `fold right', is also usually implemented as a curried function and has an even more sophisticated type than map. Its type is (('a * 'b) -> 'b) -> ('b -> (('a list) -> 'b)).

What is the type of foldr function in Haskell?

foldr type is Foldable t => (a -> b -> b) -> b -> t a -> b. So it takes 3 parameters as input.

What does foldr return?

foldr takes two arguments: A combining function and an identity value. It then returns a function that takes a list and returns an accumulated value.

What does foldr mean in Haskell?

Foldr — foldr is a higher-order function in Haskell with the following type signature: foldr :: (a -> b -> b) -> b -> [a] -> b. The easiest way to think about foldr is that it takes a list, and replace the : operator with the given function, and the empty list with the given value.

What is the folderid type of a folder?

All FolderId elements are of the FolderIdType type. The FolderId element is required in every case except in elements whose type extends the BaseFolderType or where the FolderId element is a part of a choice. Review the schema for more information.

How do I know what file types to include?

A good starting point for finding files types to include is to look at the registered file types on the computer. To find the registered file types on a computer running Windows 7 or Windows 8 Click Start.

What is the use of the folderid element?

Identifies the ID of the folder that e-mail items will be moved to. None. All FolderId elements are of the FolderIdType type. The FolderId element is required in every case except in elements whose type extends the BaseFolderType or where the FolderId element is a part of a choice. Review the schema for more information.

What is included in the collection of special folders?

The collection of special folders includes all of the system's standard virtual folders, such as Printers, My Documents, and Network Neighborhood. It also includes a number of standard file system folders, such as Program Files and System.


2 Answers

The type Foldable t => t (b -> b) -> b -> b reads as:

  • (Foldable t => ...) Choose any list-like "container" type t,
  • (t (b -> b) -> ... ) then provide as an argument a t-container of functions b -> b,
  • (b -> b) the final result will be a function b -> b.

So, it's only slightly more general than: "give me a list of functions, and I will produce a function".

Indeed, when we use lists as containers:

foldr (.) id [f1,f2,f3,...,fn]

results, by definition of foldr, in

f1 . (f2 . (f3 .  ... (fn . id) ...))

which is the composition of all the functions in the list.

So i thought that foldr (.) id should take a single parameter as input.

It does: the argument has type t (b -> b). Every function in Haskell takes a single parameter as input. E.g.

foo :: T -> U -> W -> Z

takes T and returns a function U -> W -> Z. Now, we can also say that foo takes two arguments of type T and U and returns a function W -> Z. Or That it takes three arguments T, U, and W, and returns a Z. There is no real difference between these interpretations of a type, thanks to currying, so we can pick the one which is the easiest to grasp.

In your case, the result type of foldr (.) id is b -> b, so one usually interprets the first b as an additional argument. This does not provide a good intuition, though. It's easier to think of b -> b being the result type.


More technically: the type of foldr is (renaming variables for clarity).

foldr :: Foldable t => (a -> c -> c) -> c -> t a -> c

In foldr (.) id, we can see that the type of the second argument is id :: b -> b, hence we are using c = (b -> b), as if we specialized the above type to:

foldr :: Foldable t => (a -> (b -> b) -> (b -> b)) -> (b -> b) -> t a -> (b -> b)

Now, the first argument must have type (.) :: (a -> (b -> b) -> (b -> b)) to type check. This is possible only if a = (b -> b). Hence, we specialize again.

foldr :: Foldable t => 
         ((b -> b) -> (b -> b) -> (b -> b)) ->
         (b -> b) -> 
         t (b -> b) ->
         (b -> b)

which is the final type: after this specialization, foldr can then be applied to (.) and id.

All the specializations above are inferred automatically by GHC from your code. Essentially, GHC chooses a and c in the only way that can make your code type check

like image 136
chi Avatar answered Sep 23 '22 17:09

chi


TLDR answer:

foldr (.) id :: Foldable t => t (b -> b) -> b -> b

DOES take one argument. It takes a t (b -> b) and returns a b -> b.

This confusion is usually due to Haskell allowing the omission of parens in type signatures. Parens in types associate to the right. So another way to look at this:

foldr        :: Foldable t => (a -> r -> r) -> (r       -> (t  a       ->  r))
(.) :: (c -> d) -> (b -> c) -> (b -> d)
--        a     ->    r     ->    r
(.) :: (c -> c) -> (b -> c) -> (b -> c)
foldr (.)    :: Foldable t =>                  (b -> c) -> (t (c -> c) -> (b -> c))
id           ::                                 b -> b
foldr (.) id :: Foldable t =>                               t (b -> b) -> (b -> b)

You could

resultFun = foldr (.) id [(+1), (*4)]
resultFun 5
>>> 21

Or even

foldr (.) id [(+1), (*4)] 5
>>> 21
like image 32
Fresheyeball Avatar answered Sep 25 '22 17:09

Fresheyeball