2

我正在尝试学习标准毫升的新泽西州,但我不明白如何迭代列表。

我正在尝试创建一个函数,该函数接受一个值和一个函数列表,并返回另一个字符串列表,如果当前函数在给定值时返回 true。

一个函数就是这样('a -> bool) * string,即一对函数和一个字符串的名字。

该函数是一个柯里化函数,因此其定义为“fun itr x xs”。

我想以非递归方式执行此操作。

谁能帮我开始?

4

2 回答 2

1

使用递归可以很容易地编写一个自然而直接的函数。

fun itr x fs =
  case fs
    of [] => []
     | (f, s) :: fs' => if f x
                        then s :: itr x fs'
                        else itr x fs'

或者,如果您不想在函数中显式递归,则可以使用foldr.

fun itr x fs =
  List.foldr (fn ((f, s), ss) =>
    if f x
    then s :: ss
    else ss) [] fs

此外,itr这不是一个信息量很大的名称,因此您可能需要选择一个更好地描述您正在尝试做的事情的不同名称。

于 2013-02-10T23:55:36.453 回答
0

因此,如果我理解正确,您希望能够像这样调用您的函数:

itr
    3
    [ ((fn i => i > 3), "greaterThanThree"),
      ((fn i => i mod 2 = 1), "odd"),
      ((fn i => 12 mod i = 0), "dividesTwelve")
    ]

并得到类似的结果["odd", "dividesTwelve"](因为odd和是应用到 时dividesTwelve返回的两个函数)。true3

我有这个权利吗?

因此,我们可以从编写开始:

(* Given a value and a list of named Boolean functions, returns a list of the names of the
 * functions that return true for value.
 *)
fun itr value namedFunctions =
  ...

既然您说您想“以非递归方式执行此操作”,我假设您的意思是您想要使用标准 ML 基础库中的列表函数,它允许您通过提供处理列表元素的函数来处理列表隔离; 当然,这些函数是使用递归实现的,但如果itr只是委托给它们,那么itr它本身就不需要递归。

鉴于这些要求,我看到了两种方法。


一种方法是首先使用List.filter请参阅List.filter此处的文档)在调用时仅获取namedFunctions该返回的元素。为此,我们需要一个函数,它接受一个命名函数(a ,其中是 的类型)并在命名函数返回时返回;那是:truevalue('a -> bool) * string'avaluetruetrue

(* A function that, given a named Boolean function, returns whether it returns true for
 * value.
 *)
fn (f, _) => f value

这让我们可以List.filter这样调用:

(* A list of the elements of namedFunctions that return true for value. *)
List.filter (fn (f, _) => f value) namedFunctions

一旦我们有了它,我们需要使用List.map参见List.map此处的文档)来获取每个函数的名称:

(* A list of the names in namedFunctions that return true for value. *)
List.map #2 (List.filter (fn (f, _) => f value) namedFunctions)

(其中#2是提取2元组或记录的组件的函数;在命名函数的情况下,#2 namedFunction是名称)。

把它放在一起:

(* Given a value and a list of named Boolean functions, returns a list of the names of the
 * functions that return true for value.
 *)
fun itr value namedFunctions =
  List.map #2 (List.filter (fn (f, _) => f value) namedFunctions)

另一种方法是通过使用将过滤和映射组合成一个步骤List.mapPartial(请参阅List.mapPartial此处的文档)。不是首先使用一个接受命名函数并返回布尔值的函数来选择我们想要的元素,然后使用一个接受命名函数并返回其名称的函数将它们转换为我们想要的形式,我们可以组合逐步使用一个函数,该函数接受一个命名函数并仅在我们需要时才返回其名称。

在标准 ML 中,当我们想要表示一个并不总是存在的值时,我们使用option; 例如,string option表示“要么是一个字符串,要么什么都没有”(请参阅Option.option​​此处的文档;请注意,虽然它被记录为Option.option,但它也可以作为 just 使用option)。所以,这里有一个函数,它接受一个命名函数,并且只有当它返回 true 时才返回它的名字value

(* A function that, given a named Boolean function, returns its name if it returns true
 * for value, and nothing if it returns false.
 *)
fn (f, name) => if f value then SOME name else NONE

这样的函数称为“部分函数”——它仅返回其域的一部分的值——我们可以使用List.mapPartial它仅在它返回一个的情况下检索它的结果:

(* Given a value and a list of named Boolean functions, returns a list of the names of the
 * functions that return true for value.
 *)
fun itr value namedFunctions =
  List.mapPartial (fn (f, name) => if f value then SOME name else NONE) namedFunctions

通常,任何时候您想应用List.map到结果List.filter或反之亦然,您都可以使用List.mapPartial. (然而,在任何给定的情况下,这样做可能是一个好主意,也可能不是一个好主意。我建议哪个更清楚。)

于 2015-04-19T18:31:06.373 回答