如何将泛型函数作为参数传递给另一个函数?

时间:2016-12-25 16:17:26

标签: haskell

我们说我有三个功能:

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)

我该怎么做?

2 个答案:

答案 0 :(得分:8)

早上好在评论中说,你只是根本不需要任何函数类型 - 第一顺序类型bar :: Int -> Int -> Foo -> Int将完成这项工作就好了,因为你实际上并没有提供foo函数bar 中的任何参数 - 在应用bar之前传递这些参数,即您只传递结果。感谢懒惰,foo函数是否昂贵无关紧要,因此如果不需要,你宁愿不评估它们:如果你实际上不需要它们,Haskell将确保不评估函数结果! / p>

一般来说,允许你“将通用函数作为参数传递”的东西。它被称为 Rank-2多态性

{-# 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

(如果您不是Unicode语法的粉丝,您也可以将写为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实际上不会被评估。