简体   繁体   English

使用折叠/映射比较SML中的两个列表?

[英]Comparing Two Lists in SML using Fold/Map?

Say I have two lists, [1,2,3] and [9,2,3] . 假设我有两个列表, [1,2,3][9,2,3] Say I'm given a third value, 2 . 假设我得到了第三个值2 If I want to find out if this value is in both lists, but I can only use foldl/foldr/map to do so (no let environments or custom recursion outside of map/foldr/foldl), how can I do so? 如果我想确定两个列表中是否都包含此值,但是我只能使用foldl / foldr / map来执行此操作(不允许在map / foldr / foldl之外进行环境或自定义递归操作),该怎么办? This is a homework question for a programming class and I've been stuck on it for a week now. 这是编程班的作业问题,我已经坚持了一个星期。

There is a number of things you can do to approach this assignment: 您可以采取多种措施来完成此任务:

  1. Write a stub for the function, so you know what you're dealing with: 为该函数编写一个存根,以便您知道要处理的内容:

     fun isInBoth (xs, ys, z) = ... 

    where this function returns something of type bool . 该函数返回的类型为bool

  2. Think about how you might solve this if it were just membership in one list: 考虑一下如果只是一个列表中的成员,您将如何解决此问题:

     (* Using built-in functions *) fun isInList (xs, z) = List.exists (fn x => x = z) xs (* Using recursion directly *) fun isInList ([], z) = false | isInList (x::xs, z) = x = z orelse isInList (xs, z) 
  3. Rule out the use of map , since this produces a 'b list , not a bool . 排除使用map可能性,因为这会产生一个'b列表 ,而不是布尔值
  4. Proceed to solve this using folding for just one list: 继续使用折叠仅解决一个列表来解决此问题:

     fun isInList (xs, z) = foldl (fn (x, acc) => ...) ... xs 

    where acc is the value that foldl accumulates upon each recursive call. 其中acc是在每次递归调用时foldl累积的值。

    The first ... must reflect whether the presence of the value x in the list makes a difference to the result of the function, or if any previously regarded element made a difference (using acc as a proxy). 第一个...必须反映出列表中值x的存在是否对函数的结果产生了影响,或者以前是否认为任何元素产生了影响(使用acc作为代理)。

    The second ... is a bool that represents the default value in case xs is empty, and is the base case for the recursion that foldl performs. 第二个...布尔值 ,表示xs为空时的默认值,并且是foldl执行的递归的基本情况。

    Be aware that folding in Standard ML is an eager process: It goes through the whole list, beyond when it has come to the conclusion that an element is present. 请注意,标准ML中的折叠是一个急切的过程:它遍历整个列表,而不是得出存在元素的结论。 For that reason, on average, List.exists is a better combinator for searching a single list. 因此,平均而言, List.exists是搜索单个列表的更好组合器。 In lazily evaluated languages, folding might be equivalent. 在懒惰的评估语言中,折叠可能是等效的。

  5. Proceed to solve this for two lists, trivially: 继续简单地解决两个清单:

     fun isInBoth (xs, ys, z) = isInList (xs, z) andalso isInList(ys, z) 
  6. (Optionally,) consider how one might intertwine these two recursive calls and create pairwise folding. (可选)考虑一个人如何缠绕这两个递归调用并创建成对折叠。 Actually, there's a function called ListPair.foldl that works like this: 实际上,有一个名为ListPair.foldl的函数,其工作原理如下:

     (* Finds the largest positive integer in two lists, or 0 *) fun max3 (x, y, z) = Int.max (x, Int.max(y, z)) fun maxTwoLists (xs, ys) = ListPair.foldl max3 0 (xs, ys) 

    but it comes with an annoying side-effect: 但它具有令人讨厌的副作用:

     val huh = maxTwoLists ([1,2,3], [1,2,3,4]) (* gives 3 *) 

    So if you want to iterate through two lists and regard their elements pairwise, and continue looking in the one list when the other ends, and stop folding in case your criterion is met or no longer can be met, you are dealing with a recursion scheme that neither List.foldl nor ListPair.foldl supports out of the box. 因此,如果您要遍历两个列表并成对考虑它们的元素,并在另一端继续在一个列表中查找,并在满足或不再满足条件时停止折叠,则需要处理递归方案List.foldlListPair.foldl支持开箱即用。 If this were not a school exercise that demanded folding, this would be one solution: 如果这不是要求折叠的学校练习,那么这将是一个解决方案:

     fun isInList (xs, z) = List.exists (fn x => x = z) xs fun isInBoth (x::xs, y::ys, z) = x = z andalso isInList (y::ys, z) orelse (* no needs to look at more xs *) y = z andalso isInList (x::xs, z) orelse (* no needs to look at more ys *) isInBoth (xs, ys, z) (* keep looking in both *) | isInBoth ([], ys, z) = false (* not found in xs *) | isInBoth (xs, [], z) = false (* not found in ys *) 

    Abstracting the recursion pattern into a function similar to ListPair.foldl probably isn't that useful. 将递归模式抽象成类似于ListPair.foldl的函数可能没什么用。

You can simply use some form of guarantee from the foldl function, combined with the and operator as : 您可以简单地使用foldl函数中的某种形式的保证,将and运算符组合为:

fun intersection l1 l2 v = (#1 (foldl (fn (x,y) => if (x = (#2 y)) then (true, (#2 y)) else y) (false, v) l1)) andalso (#1 (foldl (fn (x,y) => if (x = (#2 y)) then (true, (#2 y)) else y) (false, v) l2))

This is elegant, simple and in one-line (though, arguably, for style purposes you probably want it to be in more than one line). 这是优雅,简单和单行的(尽管,出于样式目的,您可能希望将它放在多行中)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM