# Is there a better way to have optional function arguments in Haskell?

Haskell## Haskell Problem Overview

I'm used to being able to define optional arguments like so in Python:

```
def product(a, b=2):
return a * b
```

Haskell doesn't have default arguments, but I was able to get something similar by using a Maybe:

```
product a (Just b) = a * b
product a Nothing = a * 2
```

This becomes cumbersome very quickly if you have more than multiple parameters though. For example, what if I want to do something like this:

```
def multiProduct (a, b=10, c=20, d=30):
return a * b * c * d
```

I would have to have eight definitions of multiProduct to account for all cases.

Instead, I decided to go with this:

```
multiProduct req1 opt1 opt2 opt3 = req1 * opt1' * opt2' * opt3'
where opt1' = if isJust opt1 then (fromJust opt1) else 10
where opt2' = if isJust opt2 then (fromJust opt2) else 20
where opt3' = if isJust opt3 then (fromJust opt3) else 30
```

That looks very inelegant to me. Is there an idiomatic way to do this in Haskell that is cleaner?

## Haskell Solutions

## Solution 1 - Haskell

Perhaps some nice notation would be easier on the eyes:

```
(//) :: Maybe a -> a -> a
Just x // _ = x
Nothing // y = y
-- basically fromMaybe, just want to be transparent
multiProduct req1 opt1 opt2 opt3 = req1 * (opt1 // 10) * (opt2 // 20) * (opt3 // 30)
```

If you need to use the parameters more than once, I suggest going with @pat's method.

**EDIT 6 years later**

With `ViewPatterns`

you can put the defaults on the left.

```
{-# LANGUAGE ViewPatterns #-}
import Data.Maybe (fromMaybe)
def :: a -> Maybe a -> a
def = fromMaybe
multiProduct :: Int -> Maybe Int -> Maybe Int -> Maybe Int -> Int
multiProduct req1 (def 10 -> opt1) (def 20 -> opt2) (def 30 -> opt3)
= req1 * opt1 * opt2 * opt3
```

## Solution 2 - Haskell

Here's yet another way to do optional arguments in Haskell:

```
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FlexibleContexts #-}
module Optional where
class Optional1 a b r where
opt1 :: (a -> b) -> a -> r
instance Optional1 a b b where
opt1 = id
instance Optional1 a b (a -> b) where
opt1 = const
class Optional2 a b c r where
opt2 :: (a -> b -> c) -> a -> b -> r
instance Optional2 a b c c where
opt2 = id
instance (Optional1 b c r) => Optional2 a b c (a -> r) where
opt2 f _ b = \a -> opt1 (f a) b
{- Optional3, Optional4, etc defined similarly -}
```

Then

```
{-# LANGUAGE FlexibleContexts #-}
module Main where
import Optional
foo :: (Optional2 Int Char String r) => r
foo = opt2 replicate 3 'f'
_5 :: Int
_5 = 5
main = do
putStrLn $ foo -- prints "fff"
putStrLn $ foo _5 -- prints "fffff"
putStrLn $ foo _5 'y' -- prints "yyyyy"
```

**Update**: Whoops, I got accepted. I honestly think that luqui's answer is the best one here:

- the type is clear, and easy to read, even for beginners
- same for type errors
- GHC doesn't need hints to do type inference with it (try
`opt2 replicate 3 'f'`

in ghci to see what I mean) - the optional arguments are order-independent

## Solution 3 - Haskell

I don't know of a better way to solve the underlying problem, but your example can be written more succinctly as:

```
multiProduct req1 opt1 opt2 opt3 = req1 * opt1' * opt2' * opt3'
where opt1' = fromMaybe 10 opt1
opt2' = fromMaybe 20 opt2
opt3' = fromMaybe 30 opt3
```

## Solution 4 - Haskell

When arguments get too complex, one solution is to create a data type just for the arguments. Then you can create a default constructor for that type, and fill in only what you want to replace in your function calls.

Example:

```
$ runhaskell dog.hs
Snoopy (Beagle): Ruff!
Snoopy (Beagle): Ruff!
Wishbone (Terrier): Ruff!
Wishbone (Terrier): Ruff!
Wishbone (Terrier): Ruff!
```

dog.hs:

```
#!/usr/bin/env runhaskell
import Control.Monad (replicateM_)
data Dog = Dog {
name :: String,
breed :: String,
barks :: Int
}
defaultDog :: Dog
defaultDog = Dog {
name = "Dog",
breed = "Beagle",
barks = 2
}
bark :: Dog -> IO ()
bark dog = replicateM_ (barks dog) $ putStrLn $ (name dog) ++ " (" ++ (breed dog) ++ "): Ruff!"
main :: IO ()
main = do
bark $ defaultDog {
name = "Snoopy",
barks = 2
}
bark $ defaultDog {
name = "Wishbone",
breed = "Terrier",
barks = 3
}
```

## Solution 5 - Haskell

A possible improvement/modification on the record-approach mentioned by mcandre and Ionuț, is to use lenses:

```
{-# LANGUAGE -XTemplateHaskell #-}
data Dog = Dog {
_name :: String,
_breed :: String,
_barks :: Int
}
makeLenses ''Dog
defaultDog :: Dog
defaultDog = Dog {
_name = "Dog",
_breed = "Beagle",
_barks = 2
}
bark :: (Dog -> Dog) -> IO ()
bark modDog = do
let dog = modDog defaultDog
replicateM_ (barks dog) $ putStrLn $
(name dog) ++ " (" ++ (breed dog) ++ "): Ruff!"
main :: IO ()
main = do
bark $ (name .~ "Snoopy") . (barks .~ 2)
bark $ (name .~ "Wishbone") . (breed .~ "Terrier") . (barks .~ 3)
```

Or alternatively

```
bark :: Dog -> IO ()
bark dog = do
replicateM_ (barks dog) $ putStrLn $
(name dog) ++ " (" ++ (breed dog) ++ "): Ruff!"
main :: IO ()
main = do
bark $ name .~ "Snoopy" $ barks .~ 2 $ defaultDog
bark $ name .~ "Wishbone" $ breed .~ "Terrier" $ barks .~ 3 $ defaultDog
```

See here for the meaning of `(.~)`

.

## Solution 6 - Haskell

Here is a way that makes Implicit Parameters look like optional arguments:

```
{-# LANGUAGE Rank2Types, ImplicitParams #-}
multiProduct :: (Num x) => x -> ((?b::x) => x) -> ((?c::x) => x) -> ((?d::x) => x) -> x
multiProduct a b c d = let ?b=10 ; ?c=20 ; ?d=30
in a * b * c * d
test1 = multiProduct 1 ?b ?c ?d -- 6000
test2 = multiProduct 2 3 4 5 -- 120
```