我正在尝试学习新泽西的标准ml,但我不明白如何迭代列表。
我正在尝试创建一个函数,它接受一个值和一个函数列表,并返回另一个字符串列表,如果当前函数在给定值时返回true。
一个函数就像这个('a -> bool) * string
,即一对函数和一个名字的字符串。
该函数是一个curried函数,因此它定义为“fun itr x xs”。
我想非递归地执行此操作。
任何人都可以帮助我开始吗?
答案 0 :(得分: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
不是一个信息量很大的名称,因此您可能想要选择一个更好地描述您正在尝试做的事情的名称。
答案 1 :(得分: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
是应用于true
时返回3
的两个函数。)
我有这个权利吗?
所以,我们可以从写作开始:
(* 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
(see List.filter
documentation here)来获取在namedFunctions
上调用时返回true
的{{1}}元素。为此,我们需要一个带有命名函数的函数(value
,其中('a -> bool) * string
是'a
的类型),如果命名函数返回{value
,则返回true
{1}};那就是:
true
这让我们可以像这样呼叫(* 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
(see List.map
documentation here)来获取每个函数的名称:
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
documentation here)。通过使用一个带有命名函数的函数并返回一个布尔值,然后通过使用一个带有命名函数并返回其名称的函数将它们转换为我们想要的形式,而不是首先只选择我们想要的元素,我们可以将它们组合起来通过使用一个带有命名函数的函数的步骤,只有在我们想要它时才返回它的名称。
在标准ML中,当我们想要表示并不总是存在的值时,我们使用List.mapPartial
;例如,option
表示“字符串或任何字符串”(see Option.option
documentation here;请注意,虽然它记录为string option
,但它也可以只用Option.option
)。所以,这是一个带有命名函数的函数,只有当它为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
组合这两个步骤。 (但是,在任何给定的例子中,这样做可能是也可能不是一个好主意。我建议任何一个更清楚。)