我们说我有三个功能:
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)
现在我希望能够在另一个函数中传递它们(f :: (???? -> Foo)
),只有在另一个昂贵的函数(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
以这种方式:
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)
我该怎么做?
答案 0 :(得分:8)
早上好在评论中说,你只是根本不需要任何函数类型 - 第一顺序类型 一般来说,是允许你“将通用函数作为参数传递”的东西。它被称为 Rank-2多态性。 (如果您不是Unicode语法的粉丝,您也可以将bar :: Int -> Int -> Foo -> Int
将完成这项工作就好了,因为你实际上并没有提供foo
函数bar
中的任何参数 - 在应用bar
之前传递这些参数,即您只传递结果。感谢懒惰,foo
函数是否昂贵无关紧要,因此如果不需要,你宁愿不评估它们:如果你实际上不需要它们,Haskell将确保不评估函数结果! / p>
{-# 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
∀
写为forall
。)
实际上,这似乎并不是您想要的应用程序。
答案 1 :(得分:2)
请将其声明为:
bar :: Int -> Int -> Foo -> Int
bar a b f = if (a == b) then a
else if (a > b) then evalSomething f
else a + b
并将其命名为:
bar 5 3 (fooThree one two three)
由于Haskell很懒惰,除非在evalSomething中需要,否则fooThree实际上不会被评估。