2

I'm trying to write something like this in Haskell:

length . nub . intersect

but it doesn't work.

*Main Data.List> :t intersect
intersect :: Eq a => [a] -> [a] -> [a]
*Main Data.List> :t nub
nub :: Eq a => [a] -> [a]
*Main Data.List> :t length
length :: [a] -> Int

Based on the type, my understanding is that intersect returns a type of [a] and donates to nub , which takes exactly a type of [a] , then also returns a type of [a] to length , then finally the return should be an Int. What's wrong with it?

Will Ness
  • 70,110
  • 9
  • 98
  • 181
user3928256
  • 903
  • 1
  • 11
  • 17
  • 1
    Actually, `intersect` returns a type of `[a] -> [a]`. `((length . nub) .) . intersect` will do what you want, but my understanding here is too weak to answer. – Franky Sep 09 '14 at 06:50
  • see also: http://www.haskell.org/haskellwiki/Pointfree#Dot – Will Ness Sep 09 '14 at 11:26

3 Answers3

6

The problem here is that intersect takes 2 arguments (in a sense)

you can provide one of the arguments explicitly:

> let f a = length . nub . intersect a
> :t f
f :: Eq a => [a] -> [a] -> Int

or you can use a fun little operator like (.:) = (.) . (.):

> let (.:) = (.) . (.)
> :t length .: (nub .: intersect)
length .: (nub .: intersect) :: Eq a => [a] -> [a] -> Int

here is a version where you don't need the parens:

import Data.List

infixr 9 .:

(.:) :: (c -> d) -> (a -> b -> c) -> a -> b -> d
(.:) = (.).(.)

f :: Eq a => [a] -> [a] -> Int
f = length .: nub .: intersect
Random Dev
  • 51,810
  • 9
  • 92
  • 119
4

I guess this is based on the comments in your previous question, where @CarstenKönig mentions (.) . (.).

First of all, length . nub . intersect cannot work. Your types are:

(.)       ::         (b -> c) -> (a -> b) -> (a -> c)
length    ::         [a] -> Int
nub       :: Eq a => [a] -> [a]
intersect :: Eq a => [a] -> [a] -> [a] ~ [a] -> ([a] -> [a])

As you can see, intersect has the wrong type, in the context of (.), the type parameter b would be replaced by ([a] -> [a]), which isn't the type of nub's first argument.

Community
  • 1
  • 1
Zeta
  • 103,620
  • 13
  • 194
  • 236
2

I'd say this: write your code the "dumb" way at first, and then refactor it to use (.). After some practice the composition operator will then become like second nature.

So you'd first write:

yourFunction xs ys = length (nub (intersect xs ys))

What (.) lets you do is get rid (syntactically) of the last argument of the innermost function, all all the parens. In this case that argument is ys:

yourFunction xs = length . nub . intersect xs
Luis Casillas
  • 29,802
  • 7
  • 49
  • 102