Reputation: 9103
Let's say I have three functions:
data Foo = Foo { x :: String, y :: String, z:: String }
fooZero :: Foo
fooZero = Foo "empty" "empty" "empty"
fooOne :: String -> Foo
fooOne a = Foo a "empty" "empty"
fooThree :: String -> String -> String -> Foo
fooThree a b c = Foo (doSomething a) (doSomethingElse b) (doAnotherThing c)
Now I want to be able to pass them (f :: (???? -> Foo)
) in another function, to be executed only in case it is required by another expensive function (evalSomething
):
bar :: Int -> Int -> (???? -> Foo) -> Int
bar a b f = if (a == b) then a
else if (a > b) then evalSomething f -- return Int
else a + b
in this way:
let one = "One"
let two = "Two"
let three = "Three"
bar 8 8 (fooZero)
bar 1 2 (fooOne one)
bar 5 3 (fooThree one two three)
How can I do that?
Upvotes: 1
Views: 1507
Reputation: 120711
As n.m. said in the comments, you simply don't need any function type at all there – the first-order type bar :: Int -> Int -> Foo -> Int
will do the job just fine, since you don't actually feed the foo
functions any arguments within bar
– those arguments are passed before applying bar
, i.e. you only pass the result. Thanks to lazyness it won't matter if the foo
functions are expensive so you'd rather not evaluate them if not needed: Haskell will make sure function results aren't evaluated if you don't actually need them!
Generally speaking, there is a thing that allows you to “pass generic functions as parameters” though. It's called Rank-2 polymorphism.
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE UnicodeSyntax #-}
bar :: Int -> Int -> (∀ t . Monoid t => t -> Foo) -> Int
bar a b f
| a == b = a
| a > b = f (mempty :: [])
| otherwise = a + b
(If you're not a fan of Unicode syntax, you can also write ∀
as forall
.)
That doesn't actually seem to be what you want for your application though.
Upvotes: 8
Reputation: 7187
Just declare it as:
bar :: Int -> Int -> Foo -> Int
bar a b f = if (a == b) then a
else if (a > b) then evalSomething f
else a + b
And call it as:
bar 5 3 (fooThree one two three)
Since Haskell is lazy, fooThree won't actually be evaluated unless it's needed inside evalSomething.
Upvotes: 2