【问题标题】:SML map a filter?SML映射过滤器?
【发布时间】:2019-05-19 04:59:11
【问题描述】:

如果我有这个代码:

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

但这并不能真正起作用,因为正如所指出的那样,map 中的coord_select 实际上是在尝试返回一个列表——map 如何知道插入fs 的成员首先进入f? Common Lisp 确实有一个设备来阻止这样的函数运行,即' 运算符。但这也无济于事,因为map 不知道fs 提供的是哪个变量。对于输入,例如,我有这些坐标:

[(2,2),(2,3),(3,3),(4,3)]

我有这个 x 坐标列表来匹配上面的列表

[3,4]

同样,我可以对此进行递归包装,但我正在从更大的 fold 家族中寻求更优雅的嵌套解决方案。

【问题讨论】:

  • 先算出所有类型。例如,coord_select (f, cs) 是一个(int * int) list,而不是一个函数(或者,如果存在f,则将是一个函数),并且将'a -> 'b list 函数映射到'a list 将产生'b list list,而不是@987654345 @。 (提示:研究折叠。)
  • 我想我现在明白了。 IOW,我在map 中的coord_select (f, cs) 正在返回一个元组列表,即它不是一个适用的函数。唉,初学者的不走运....
  • Conditional in ML map的可能重复
  • @Simon Shine:这是一个延续。唯一不同的是,之前,我只让它过滤一个坐标值。这次是值列表。实际上,您的filter 建议就是我解决它的方法。请参阅上文了解我是如何实现它的。
  • @147pm:在这种情况下,您的要求有点不清楚。既然你问的是一个是/否的问题,你会满足于“是”吗?也许如果您扩展了您正在做的事情并将问题包含在一个问答中,而不是针对学习过程中的每个步骤一个问答,这将不符合“重复”或“不清楚”或@ 987654322@.

标签: sml fold


【解决方案1】:

如果我不将所需的第一个坐标作为 int 给出,而是作为几个所需的第一个坐标的列表,例如 [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

但应该很明显,显式折叠不是很可读。

如果有一个专门的组合器可以完成一项工作,那么您宁愿希望它胜过折叠。如果它不存在,从稍微不太专业的组合器创建它可以提高可读性。折叠与您所获得的手动递归一样接近,因此向读者提供的关于我们正在尝试哪种递归的信息很少。

出于这个原因,我还从exists 创建了member,因为exists 要求我指定一个谓词,而我的谓词是“与x 相等”;所以我觉得即使是exists 也会给coord_select 函数添加混乱。

您可以通过阅读 Meijer、Fokkinga、Paterson 的 Functional Programming with Bananas, Lenses, Envelopes and Barbed Wire (1991) 了解更多关于函数式编程中列表变态的信息。

【讨论】:

  • 谢谢。使用exists 然后filter 做得更优雅,尽管从一个第一个坐标到第一个坐标列表的复杂性增加已被证明有点令人生畏。我对member 如何巧妙地提供布尔值印象深刻,就像filter 的条件部分所期望的那样。我错过了这一点,即filter 想要truefalse 一个“它存在吗?”这正是我想要的学习体验。我希望其他人也能从中受益。
猜你喜欢
  • 2011-04-10
  • 2014-07-23
  • 2021-12-05
  • 2010-10-23
  • 2020-11-22
  • 2011-05-11
  • 2019-01-30
  • 2013-10-05
  • 1970-01-01
相关资源
最近更新 更多