Как Вы пишете функцию, которая может или возвратить значение или другую функцию?
Например:
Function Foo (x)
If X = 0 Return "Done"
Else Return a Function that calls Foo(x-1)
В haskell тип возвращаемого значения функции может зависеть только от типа ее аргументов и, в случае функций с полиморфными типами возврата, от того, как используется возвращаемое значение. В частности, тип возвращаемого значения функции не может зависеть от значения аргумента.
Другими словами: вы не можете делать то, что хотите, напрямую. В случаях, когда вы хотите вернуть один из двух типов, обычно можно использовать тип Либо a b
, который определен как данные, либо a b = Left a | Right b
, что позволяет вам возвращать значение типа a
, заключенное в Left
, или значение типа b
, заключенное в Правильно
. Затем вы можете использовать сопоставление с образцом, чтобы получить значение безопасным способом.
Однако, поскольку в этом случае тип для 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, потому что он ленив, и вещи обычно не оцениваются до того, как они будут использованы.
Судя по вашему псевдокоду, я предполагаю, что вы ожидаете вернуть "нулевую" функцию, то есть такую, которая не принимает аргументов и при вызове вызывает 'Foo(x-1)'.
Если это так, то, как указано в конце ответа sepp2k, в Haskell есть такая необходимость - это то, что происходит по умолчанию. Specifically:
foo x = if x == 0 then "Done"
else foo(x-1)
делает именно это: Значение, возвращаемое вызовом, скажем, foo(7)
- это такая штука, которая, когда программе понадобится ее значение, оценит foo(6)
. Рекурсивный вызов не будет оценен внутри оценки выражения if
.
Вам нужно подумать о типах вашей функции: если Foo имеет тип (Int -> t), что такое t? В обоих случаях он должен возвращать что-то типа t. Я думаю, что это немного сложно, потому что я не думаю, что t может быть типом String или типом функции (->) в одной и той же функции.
Я знаю, что это не является прямым ответом на ваш вопрос, но я думаю, что вам нужно расширить свое представление о том, что значит "вернуть функцию". Например, функцию:
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
Просто продолжение отличного ответа sepp2k.Я думаю, вам не хватает фундаментальной концепции Haskell - вы всегда возвращаете функцию. Даже своего рода «ценность» - это функция.
Например, откройте ghci и попробуйте:
> :t 5
:: (Num t) => t
Просто функция, которая не принимает входных данных, возвращаемое значение - Num.
> :t "What is this?"
:: [Char]
Точно так же функция, которая не принимает значения, возвращает [Char]
«Но это все просто значения! Я не уверен!»
Что же тогда главное? (Предположим, вы определили его):
> :t main
:: IO ()
Просто функция, которая возвращает экземпляр IO ().
{-# LANGUAGE ExistentialQuantification #-}
data MyResult = Str String | forall a. Fun a -- deriving Show
foo 0 = Str "done"
foo x = Fun (\ () -> foo (x-1))
это вроде как работает, но вы не можете вывести экзистенциальный тип (я думаю), поэтому вам нужно вызвать foo вот так: (\(Main.Str x) -> x) (Main.foo 0)
.
Если вы знаете, как получить модуль Main в фокусе в ghci, пожалуйста, опубликуйте комментарий.
foo x =
if x<=0 then "Done"
else foo2 (x)
foo2 x = foo (x-1) ++ foo (x-1)
Нашел нетривиальный пример. Кажется, это работает.