13

Say I have a mean function defined like so:

mean xs = sum xs / (fromIntegral $ length xs)

but I want it in some tacit form, like this:

mean = sum / (fromIntegral . length)

Is there a built-in Haskell way to do something along these lines without having to build up my own tacit function (something like this):

tacit :: (a -> b -> c) -> (d -> a) -> (d -> b) -> d -> c
tacit a b c i = a (b i) (c i)

In this form, the function looks like this:

mean = tacit (/) sum (fromIntegral . length)

but it feels like there might be a way to avoid having to use an explicit function such as this. I'm just wondering; is there some way to do this that is built in to Haskell?

Will Ness
  • 70,110
  • 9
  • 98
  • 181
Benjamin Kovach
  • 3,190
  • 1
  • 24
  • 38
  • 2
    See http://squing.blogspot.com/2008/11/beautiful-folding.html, http://conal.net/blog/posts/more-beautiful-fold-zipping – sdcvvc Aug 21 '12 at 20:13
  • 1
    The technical term for what you call "tacit" is "point free" (or sometimes "pointless" for people being sarcastic). The term "point" comes from topology, and it actually refers to the variables. – Paul Johnson Aug 22 '12 at 19:18
  • @PaulJohnson, "tacit" is the term used by the J programming language (and maybe others?) to refer to what is more commonly known as "point free". – Alex R Aug 30 '12 at 16:06

2 Answers2

20

Applicative functors work pretty well here.

import Control.Applicative

mean = (/) <$> sum <*> (fromIntegral . length)
Emily
  • 2,577
  • 18
  • 38
14

Yes, your tacit function is liftM2 in the (->) r monad (liftM2 is in Control.Monad, and the function instance of Monad is in Control.Monad.Instances).

I found this using the pointfree program (you can install it via cabal install pointfree), invoked as:

$ pointfree '\xs -> sum xs / (fromIntegral $ length xs)'

(in a Unix terminal)

huon
  • 94,605
  • 21
  • 231
  • 225
  • 8
    And then you can make a `Num` instance for `(->) r` and then `mean = sum / (fromIntegral . length)` will actually work. – Sjoerd Visscher Aug 21 '12 at 19:51
  • 5
    @SjoerdVisscher: you need `Fractional` too because of `(/)`. Just tried it and confirmed that's all you need. – Luis Casillas Aug 21 '12 at 20:11
  • 4
    And an amusing addition to that is that once you have the `Num r => Num (a -> r)` instance, you can add addition to itself: `(+) + (+)` becomes a well-typed expression (equivalent to `\x y -> (x + y) + (x + y)`). – Luis Casillas Aug 21 '12 at 21:10
  • 3
    @sacundim Ah, right. And `1 2 3 4` is also a well-typed expression. It's clear why this is not a built-in instance. – Sjoerd Visscher Aug 21 '12 at 22:33
  • 2
    Heh, I didn't think of that one. But what makes it worse is that if a module of yours imports any module that uses this instance directly or indirectly, you're going to get this instance. So one should really wrap it with a `newtype`—in which case the extra syntactic overhead means that you might as well use `Applicative`. – Luis Casillas Aug 21 '12 at 22:44
  • @Sjored, OK, I give in, what does 1 2 3 4 give you? – Paul Johnson Aug 22 '12 at 19:21
  • 1
    @PaulJohnson, `1`, assuming `fromIntegral = const . fromIntegral`. – huon Aug 22 '12 at 19:33
  • As the maintainer of pointfree, I ought to point out (no pun intended) that most of the testsuite currently fails (has been doing so since before I inherited it, I might add!) – Ben Millwood Aug 30 '12 at 16:41