如何"返回"一个函数的输入,没有使用输入上的函数? (球拍)

时间:2018-04-03 20:21:51

标签: functional-programming return racket

简介

嗨,我是Racket的新手,也是功能语言的新手,因此我很难做到简单的事情(特别是当互联网上没有太多的资料时)

实际问题:

我开始编写一个函数,给出列表的最大值和最小值。因此,该函数接收2个变量,一个是列表,第二个是一个列表,其中最多只保留2个变量和最小值。 然后当" list"为null表示我查看了列表中的所有变量。这意味着我想"返回" maxMin列表,但当然功能语言不会这样工作。

怎么做?

以下是我想要实现的目标:

#lang pl
(define (maxMin list maxiMini)
  (if (null? list)
      ;return the max and min from list when finished looking at the list
      (maxiMini)
       ; else do other things
      )
  )

2 个答案:

答案 0 :(得分:3)

您要找的是continuation。 (作为旁注,使用Racket的exception handling系统也可以在这里工作。如果您可以在此处重写代码以使用with-handlers而不是let/ec,则可以获得奖励积分。)

虽然延续的大部分用途都非常强大,但这种特殊模式是相当标准的,而IMO对它们来说是少数很好的用途之一。基本上,延续就像C语言中的控制流语句(breakcontinuereturngotoyield等),除了这些语言,那些控制流语句是关键字,在Racket中,continuation是一等值。

这意味着你可以在技术上返回另一个函数return语句,并且在调用它时,代码会在第一次返回时返回到大致其状态。因此,您可以制作生成器模式。如果你不小心的话,你可以看到它如何变得非常复杂。

然而,如果你不想回归' (可以这么说)延续,你可以使用更简单(和更轻的重量)逃脱延续。这些工作与C中的setjumplongjmp非常相似。您可以使用它们从内部上下文返回,但如果控制流离开了转义延续的范围,则堆栈不能重建。 (基本上,转义延续可以弹出堆栈帧,但它们无法恢复类似的常规延续。)

Racket有一个很好的形式来创建转义延续let/ec,它创建一个转义延续。调用时,整个表达式求值为转义延续的值。例如,以下函数通常会计算为4

(define (looper)
  3
  4)

> (looper)
4

但是如果我们插入一个转义延续(让我们称之为return),它会从函数中提前返回,从而导致它被评估为3:

(define (looper2)
  (let/ec return
    (return 3)
    4))

> (looper2)
3

您可以看到如何将其嵌入到您希望提前返回的大型函数中:

(define (large-function)
  (let/ec return 
    ... lots of code ...
    (when some-condition
      (return some-value))
    ... lots of code ...))

当然,大多数时候你想要像这样早点回归,因为它有一些特殊的状态,这就是为什么我强烈建议你只使用Racket的异常处理系统。您可以使用raise抛出异常,并使用with-handlers捕获一个异常。

答案 1 :(得分:2)

这是一个返回一些东西的函数:

(define (min a b)
  (if (< a b)
      a
      b))

这将“返回”if的结果。 if“根据a”返回的内容返回“b(< a b)的评估”。

我在引号中写“返回”,因为在lisp langauges中通常会说“表达式求值为”。想象一下:

(min 5 10)

上面的表达式求值为5 ..如果要将结果放在另一个表达式中:

(+ (min 5 10) 1)

然后(min 5 10)评估为5,这是+1一起应用的第一个值6,然后评估为<

另请注意,变量 (< 4 5)会对某个函数求值,因此尝试像a一样调用它,但是b(a)是数字,不能像a那样调用。它不会起作用。如果您熟悉algol语言,则与变量a()相同,这是一个数字,并使用它--output-fzn-to-stdout