Haskell:有时返回函数的函数

时间:2010-07-04 01:01:37

标签: haskell types functional-programming

如何编写可以返回值或其他函数的函数?

例如:

Function Foo (x)
    If X = 0 Return "Done" 
    Else Return a Function that calls Foo(x-1)

8 个答案:

答案 0 :(得分:20)

在haskell中,函数的返回类型只能依赖于其参数的类型,如果是具有多态返回类型的函数,则返回值的使用方式。特别是函数的返回类型不能取决于参数的值。

换句话说:你不能直接做你想做的事。如果您想要返回两种类型中的一种,通常可以使用Either a b类型定义为data Either a b = Left a | Right b,它允许您返回包含在{a中的Left类型的值{1}}或b中包含的Right类型的值。然后,您可以使用模式匹配以类型安全的方式检索值。

但是,在这种情况下,b的类型必须是无限的,这不起作用,你必须为此定义自己的包装类型。像这样:

data MyResult = Str String | Fun ( () -> MyResult)
foo 0 = Str "done"
foo x = Fun (\ () -> foo (x-1))

foo现在有Num a => a -> MyResult类型。但是每当你调用foo时,你必须进行模式匹配,看看是否有一个带有字符串的Str或带有函数的Fun。

另请注意,如果您想要返回一个函数而不是一个值来延迟执行,那么在haskell中这没有意义,因为它是惰性的,并且在使用它们之前通常不会对它们进行评估。

答案 1 :(得分:3)

从伪代码的外观来看,我猜你期望返回一个“nullary”函数,即不带参数的函数,并在调用时调用'Foo(x-1)'。 / p>

如果是这样的话,那么正如sepp2k的答案结尾所指出的那样,Haskell中存在这样的需求 - 这就是默认情况下会发生的事情。具体做法是:

foo x = if x == 0 then "Done"
                  else foo(x-1)

完全这个:调用返回的值,比如foo(7),当程序需要它的值时,它会评估foo(6)。递归调用不会在if表达式的评估中进行评估。

答案 2 :(得分:1)

您需要考虑函数的类型:如果Foo是类型(Int - > t),那么t是什么?在两种情况下都需要返回t类型的东西。我认为这有点难,因为我不认为在同一个函数中可以是字符串类型或函数类型( - >)。

答案 3 :(得分:1)

我知道这不会直接回答你的问题,但我认为你需要扩展你对“返回一个函数”意味着什么的想法。例如功能:

mean3 :: Float -> Float -> Float -> Float
mean3 x y z = (x + y + z) / 3

可以被认为是“取3个数字并返回一个数字”。或者它可以被认为是“一个函数取两个数字,并将函数从数字返回到数字”:

mean3 :: Float -> Float -> (Float -> Float)

mean1 :: (Float -> Float)
mean1 = mean3 1 2

答案 4 :(得分:1)

刚刚接受sepp2k的好回答。我认为你在Haskell中缺少一个基本概念 - 你总是返回一个函数。即使是各种“价值”也是一种功能。

例如,胸围打开ghci并尝试:

> :t 5
:: (Num t) => t

只是一个不输入的函数,返回值是Num。

> :t "What  is this?"
:: [Char]

同样,只是一个没有值的函数,返回[Char]

“但这些都只是价值观!我不相信!”

那么主要的是什么? (假设你已经定义了它):

> :t main
:: IO ()

只是一个返回IO()实例的函数。

答案 5 :(得分:0)

{-# LANGUAGE ExistentialQuantification #-}

data MyResult = Str String | forall a. Fun a -- deriving Show

foo 0 = Str "done"
foo x = Fun (\ () -> foo (x-1))

那种作品,但是你不能派生出存在类型(methinks)所以你需要像这样调用foo:(\(Main.Str x) -> x) (Main.foo 0)

如果您知道如何让主模块成为焦点,请发表评论。

答案 6 :(得分:0)

通常,我们将其写为

foo _ = "Done"

或者,毫无意义地,

foo = const "Done"

(当然,除非我们真的想让_|_为负数; - )

答案 7 :(得分:-1)

foo x =
    if x<=0 then "Done"
            else foo2 (x)

foo2 x = foo (x-1) ++ foo (x-1)

找到了一个非常重要的例子。这似乎有效。