如果我有此代码:
fun coord_select (x : int, cs : (int*int) list) =
List.filter (fn (first, _) => first = x ) cs
使用输入进行测试可以得到:
coord_select (2, [(2,2),(2,3),(3,3),(4,3)])
: val it = [(2,2),(2,3)] : (int * int) list
现在,如果我没有将所需的第一坐标作为int
给出,而是将其作为几个所需的第一坐标(例如[3,4])的列表,那该怎么办,也就是说,我希望所有以3个和4个?一种简单的方法就是围绕该列表创建一个递归包装,该包装通过列表并将值插入为coord_select
的第一个变量。但是我想比这种强力方法更好地理解嵌套事物。所以我想出了这个:
fun coord_match (fs : int list, cs :(int*int) list) =
map (coord_select (f, cs)) fs
但是这实际上不能起作用,因为正如指出的那样,coord_select
中的map
实际上正在尝试返回列表-以及map
如何知道如何插入fs
的成员首先进入f
? Common Lisp确实具有一种设备来阻止此类功能运行,即'
运算符。但这又无济于事,因为map
不知道正在提供哪个变量fs
。对于输入,例如,我有以下坐标:
[(2,2),(2,3),(3,3),(4,3)]
并且我有这个x坐标列表与上面的列表匹配
[3,4]
同样,我可以为此设置一个递归包装器,但是我正在从更大的fold
系列中寻求一种更为优雅的嵌套解决方案。
答案 0 :(得分:1)
如果我没有将所需的第一个坐标作为整数给出,而是作为多个所需的第一个坐标(例如[3,4])的列表给出的,即我希望所有以3和4开头的坐标元组>
听起来好像您希望所有以3 或 4开头的坐标元组,因为一个坐标不能同时是3 和 4。
鉴于此,您可以像这样写coord_select
:
fun member (x, xs) =
List.exists (fn x2 => x = x2) xs
fun coord_select (xs, coords) =
List.filter (fn (x, _) => member (x, xs)) coords
fold
个大家庭
这个家庭称为catamorphisms,其中map
,filter
,exists
和foldl
属于其中。由于foldl
是最通用的方法,因此在技术上可以完全使用折叠来编写上述代码:
fun coord_select (xs, coords) =
foldr (fn ((x, y), acc1) =>
if foldl (fn (x2, acc2) => acc2 orelse x = x2) false xs
then (x, y) :: acc1
else acc1) [] coords
但是很明显,显式折叠不是很可读。
如果有专门的组合器来完成工作,那么您宁愿将它折叠起来。而且,如果不存在,则可以通过不那么专业的组合器创建它来提高可读性。折叠与您获得的手动递归非常接近,因此对于读者来说,我们尝试使用哪种递归的信息很少。
因此,我还从member
中提取了exists
,因为exists
要求我指定一个谓词,而我的谓词是“与x
相等”;因此,即使我认为exists
也会给coord_select
函数增加混乱。
通过阅读Meijer,Fokkinga,Paterson的Functional Programming with Bananas, Lenses, Envelopes and Barbed Wire(1991年),您可以了解更多有关函数编程中的列表变态的信息。