Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Binding functions that take multiple arguments

Tags:

haskell

monads

After reading some very basic haskell now I know how to "chain" monadic actions using bind, like:

echo = getLine >>= putStrLn

(>>=) operator is very handy in this fashion, but what if I want to chain monadic actions (or functors) that take multiple arguments?

Given that (>>=) :: m a -> (a -> m b) -> m b it seems like (>>=) can supply only one argument.

For example, writeFile takes two arguments (a FilePath and the contents). Suppose I have a monadic action that returns a FilePath, and another action that returns a String to write. How can I combine them with writeFile, without using the do-notation, but in a general way?

Is there any function with the type: m a -> m b -> (a -> b -> m c) -> m c that can do this?

like image 742
thkang Avatar asked Mar 01 '14 14:03

thkang


People also ask

Can a function take multiple arguments?

Functions can accept more than one argument. When calling a function, you're able to pass multiple arguments to the function; each argument gets stored in a separate parameter and used as a discrete variable within the function.

Can we pass multiple arguments inside the bind () and call () methods?

You can bind multiple arguments multiple times, exactly as partial application, but the context object only once, you can't override it once you bound it, because this is defined by specs that I linked: "The bind() function creates a new function (a bound function) with the same function body (internal call property in ...

How many arguments can a function have?

Except for functions with variable-length argument lists, the number of arguments in a function call must be the same as the number of parameters in the function definition. This number can be zero. The maximum number of arguments (and corresponding parameters) is 253 for a single function.

Can a Python function take unlimited number of arguments?

Unlimited Number of Positional Argument ValuesPython lets us define a function that handles an unknown and unlimited number of argument values. Examples of built-in functions with a unlimited number of argument values are max and min .


2 Answers

TL;DR:

writeFile <$> getFilename <*> getString >>= id   :: IO ()

Monads are Applicative

Since ghc 7.10 every Monad (including IO) is also an Applicative, but even before that, you could make an Applicative out of any Monad using the equivalent of

import Control.Applicative -- not needed for ghc >= 7.10

instance Applicative M where
  pure x = return x
  mf <*> mx = do
    f <- mf
    x <- mx
    return (f x)

And of course IO is a functor, but Control.Applicative gives you <$> which can be defined as f <$> mx = fmap f mx.

Use Applicative to use functions that take as many arguments as you like

<$> and <*> let you use pure functions f over arguments produced by an Applicative/Monadic computation, so if f :: String -> String -> Bool and getFileName, getString :: IO String then

f <$> getFileName <*> getString :: IO Bool

Similarly, if g :: String -> String -> String -> Int, then

g <$> getString <*> getString <*> getString :: IO Int

From IO (IO ()) to IO ()

That means that

writeFile <$> getFilename <*> getString :: IO (IO ())

but you need something of type IO (), not IO (IO ()), so we need to either use join :: Monad m => m (m a) -> m a as in Xeo's comment, or we need a function to take the monadic result and run it, i.e. of type (IO ()) -> IO () to bind it with. That would be id then, so we can either do

join $ writeFile <$> getFilename <*> getString :: IO ()

or

writeFile <$> getFilename <*> getString >>= id :: IO ()
like image 76
AndrewC Avatar answered Sep 29 '22 08:09

AndrewC


It's much easier to use do notation for this, rather than asking for a combinator

action1 :: MyMonad a
action2 :: MyMonad b
f :: a -> b -> MyMonad c

do
    x <- action1
    y <- action2
    f x y
like image 39
Tom Ellis Avatar answered Sep 29 '22 06:09

Tom Ellis