SML映射过滤器?

时间:2018-12-18 18:04:05

标签: sml fold

如果我有此代码:

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系列中寻求一种更为优雅的嵌套解决方案。

1 个答案:

答案 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,其中mapfilterexistsfoldl属于其中。由于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年),您可以了解更多有关函数编程中的列表变态的信息。