Question

I want to apply a 3 argument function in different ways based on a boolean value (one of the arguments).

I'd like to be able to apply it in an infix manner so I can chain it (example below). something like the following but that actually works.

f :: Bool -> a -> a -> a

f True  i j = i
f False i j = j

... y `(f True)` z `(f False)` b

Do I need to have the Bool as the second variable? Or something else? I'm kind of lost.

P.S. the reason I wanted to do this was to have optional append function

Was it helpful?

Solution

The infix notation for functions with more than two arguments is possible but not very nice. In your case, given

f :: Bool -> a -> a -> a
f True i j = i
f False i j = j

you can write

(True `f` 1) 3

It's much easier (as suggested by others) to write:

let ft = f True
let ff = f False

then you can do

1 `ft` 3 `ff` 5

If you want to use f you should write:

(False `f` ((True `f` 1) 3)) 5

You can verify that

1 `ft` 3 `ff` 5 == (False `f` ((True `f` 1) 3)) 5

OTHER TIPS

You can use a reverse application operator to achieve a similar effect. However, for every operator fixity you will have to define its own pair of operators.

This works:

infixl 5 -|
(-|) :: a -> (a -> b) -> b
(-|) = flip ($)

infixl 5 |-
(|-) :: (a -> b) -> a -> b
(|-) = ($)

infixr 5 =|
(|=) :: (a -> b -> c) -> b -> (a -> c)
(|=) = flip

infixr 5 |=
(=|) :: a -> (a -> c) -> c
(=|) = (-|)

f b x y = if b then x else y

main = do
    putStrLn $ "qwe" -| f True |- "asd" -| f False |- "kojo"
    putStrLn $ "qwe" =| f True |= "asd" =| f False |= "kojo"

And prints:

kojo
qwe

Here -| and |- brackets enclose left-associative infix expressions and =| and |= enclose right-associative expressions.

Be wary that as those are just pairs of independent operators, error messages when misusing them may be quite obscure.

While infix expression syntax have been proposed, they have not been adopted, to the best of my knowledge.

You might consider using if then else ternary functions, like so:

infix 0 ?
(?) :: Bool -> (t, t) -> t
c ? (t, e) = if c then t else e

Well, for one thing, f would have type f :: Bool -> a -> a -> a

See http://www.haskell.org/haskellwiki/Infix_operator#Using_prefix_functions_with_infix_notation for more information on using prefix functions in an infix setting.

Hopefully somebody else is wiser and can explain why

1 `f True` 3 

doesn't work, since

ft = f True
1 `ft` 3

works fine, and this seems to violate referential transparency...

It would seem that there isn't a "nice", easy way to do this, but I'm sure there's some higher level pattern that this fits, or you could do something with, e.g., zipWith or folds...

Why do you need the boolean function at all? If the value is never used, why not define f as

f :: a -> a -> a  
f i j  
i `f` j

If the boolean is really needed, then as Pvital suggested, create a ftrue and ffalse and use those.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top