什么是“命名让”?以及如何使用它来实现地图功能? [英] What is "named let" and how do I use it to implement a map function?

查看:118
本文介绍了什么是“命名让”?以及如何使用它来实现地图功能?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对Scheme完全陌生,我试图实现自己的地图功能。我试图在网上找到它,但是我遇到的所有问题都是关于一些复杂版本的map函数(比如将两个列表作为输入的映射函数)。

我设法找到的最佳答案在这里:( For - 计划中的每一个和地图)。下面是这个问题的代码:

 (define(map func lst)
(let recur((rest lst ))
(if(null?rest)
'()
(cons(func(car rest))(recur(cdr rest))))))

它不能解决我的问题,因为使用了一个不明确的函数 recur 。这对我没有意义。



我的代码如下所示:

 <$ c(c)(定义(mymap f L)
(cond((null?L)'())
(f(car L))
L))))))

当使用这种语言进行编程时,我理解功能方法背后的逻辑,但是我一直在编码时遇到很大困难。

您发布的第一个代码片段实际上是一种实现方式地图功能。它使用一个名为let。查看我对网址的评论,了解它的工作原理。它基本上是一个递归函数的抽象。如果您要编写一个可以打印所有数字(从10到0)的函数,您可以将它写出来。

 (define(printer x )
(display x)
(if(> x 0)
(printer( - x 1))))

然后调用它:

$ p $ (打印机10)

但是,既然它只是一个循环,你可以使用一个命名的let来编写它:

 (let loop((x 10))
(display x)
(if(> x 0)
循环( - x 1))))

正如Alexis King指出的,这个命名为let的语法糖立即被称为lambda。

 (letrec((loop(lambda(x)
(显示x)
(如果(> x 0)
(loop( - x 1))))))
(loop 10))

尽管是 letrec ,但并不特别。它允许表达式(在本例中为lambda)自己调用。这样你可以做递归。更多关于 letrec here



现在对于你写的地图函数,你几乎就在那里。你最后两个案件有问题。如果列表不是空的,你想取第一个元素,将你的函数应用到它,然后将函数应用到列表的其余部分。我想你误解了你实际写下的内容。生病了。



回想一下,条件子句是这样形成的:

 (cond(test1?后果)
(test2?后果2)
(别人身体))

您有任何数量的测试带有强制性后果。您的评估人员将执行 test1?,如果评估结果为 #t ,它将执行结果作为整个结果有条件的。如果 test1? test2?失败,它将执行 elsebody
$ b



Sidenote



#f (假)外。例如:

 (if(lambda(x)x)
1
2)

如果 test将会评估为 1 因为 if test会检查(lambda(x)x)是否真的,这是。这是一个拉姆达。 Truthy值是在预期真值的表达式中评估为真的值(例如,如果和 cond ) 。





现在为您的cond。你的 cond 的第一个例子会测试 L 是否为空。如果评估结果为 #t ,则返回空列表。这确实是正确的。第二种情况((f(car L)))在空列表上映射的东西只是空列表。

>)的字面意思是如果 f 为true,则返回L的 car >。
$ b $ < else case指出否则,返回结果 mymap 在我的清单中的其余部分 L



我认为你真的想要做的是使用如果测试。如果列表为空,则返回空列表。如果它不为空,则将该函数应用于列表的第一个元素。将函数映射到列表的其余部分,然后将函数的第一个元素的结果添加到该结果中。

 (cond((null?L)'())
(f(car L))
(else(mymap(f(cdr L ))))))

所以你想看看这个:

 (define(mymap f L)
(cond((null?L)'())
(else
(cons(f(car L))
(mymap f(cdr L))))))

使用 if

 (define(mymap ($ L $)
(if(null?L)'()
(cons(f(car L))
(mymap f(cdr L)))))

既然您是Scheme的新手,那么这个函数就可以做到。尝试并理解它。但是,有更好更快的方法来实现这种功能。阅读此页面,了解诸如累加器函数和尾递归等内容。我不会详细介绍一切,因为它1)不是问题,2)可能是信息超载。


I'm totally new to Scheme and I am trying to implement my own map function. I've tried to find it online, however all the questions I encountered were about some complex versions of map function (such as mapping functions that take two lists as an input).

The best answer I've managed to find is here: (For-each and map in Scheme). Here is the code from this question:

(define (map func lst)
  (let recur ((rest lst))
    (if (null? rest)
      '()
      (cons (func (car rest)) (recur (cdr rest))))))

It doesn't solve my problem though because of the usage of an obscure function recur. It doesn't make sense to me.

My code looks like this:

(define (mymap f L)
  (cond ((null? L) '())
    (f (car L))
    (else (mymap (f (cdr L))))))

I do understand the logic behind the functional approach when programming in this language, however I've been having great difficulties with coding it.

解决方案

The first code snippet you posted is indeed one way to implement the map function. It uses a named let. See my comment on an URL on how it works. It basically is an abstraction over a recursive function. If you were to write a function that prints all numbers from 10 to 0 you could write it liks this

(define (printer x)
  (display x)
  (if (> x 0)
      (printer (- x 1))))

and then call it:

(printer 10)

But, since its just a loop you could write it using a named let:

(let loop ((x 10))
  (display x)
  (if (> x 0)
      (loop (- x 1))))

This named let is, as Alexis King pointed out, syntactic sugar for a lambda that is immediately called. The above construct is equivalent to the snippet shown below.

(letrec ((loop (lambda (x) 
              (display x)
              (if (> x 0)
                  (loop (- x 1))))))
  (loop 10))

In spite of being a letrec it's not really special. It allows for the expression (the lambda, in this case) to call itself. This way you can do recursion. More on letrec and let here.

Now for the map function you wrote, you are almost there. There is an issue with your two last cases. If the list is not empty you want to take the first element, apply your function to it and then apply the function to the rest of the list. I think you misunderstand what you actually have written down. Ill elaborate.

Recall that a conditional clause is formed like this:

(cond (test1? consequence)
      (test2? consequence2)
      (else   elsebody))

You have any number of tests with an obligatory consequence. Your evaluator will execute test1? and if that evaluated to #t it will execute the consequence as the result of the entire conditional. If test1? and test2? fail it will execute elsebody.


Sidenote

Everything in Scheme is truthy except for #f (false). For example:

(if (lambda (x) x) 
    1
    2)

This if test will evaluate to 1 because the if test will check if (lambda (x) x) is truthy, which it is. It is a lambda. Truthy values are values that will evaluate to true in an expression where truth values are expected (e.g., if and cond).


Now for your cond. The first case of your cond will test if L is null. If that is evaluated to #t, you return the empty list. That is indeed correct. Mapping something over the empty list is just the empty list.

The second case ((f (car L))) literally states "if f is true, then return the car of L".

The else case states "otherwise, return the result mymap on the rest of my list L".

What I think you really want to do is use an if test. If the list is empty, return the empty list. If it is not empty, apply the function to the first element of the list. Map the function over the rest of the list, and then add the result of applying the function the first element of the list to that result.

(define (mymap f L)
  (cond ((null? L) '())
        (f (car L))
        (else (mymap (f (cdr L))))))

So what you want might look look this:

(define (mymap f L)
  (cond ((null? L) '())
        (else
         (cons (f (car L)) 
               (mymap f (cdr L))))))

Using an if:

(define (mymap f L)
  (if (null? L) '()
      (cons (f (car L)) 
            (mymap f (cdr L)))))

Since you are new to Scheme this function will do just fine. Try and understand it. However, there are better and faster ways to implement this kind of functions. Read this page to understand things like accumulator functions and tail recursion. I will not go in to detail about everything here since its 1) not the question and 2) might be information overload.

这篇关于什么是“命名让”?以及如何使用它来实现地图功能?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆