方案:返回一个函数?

时间:2016-05-11 00:35:35

标签: scheme

我试图创建一个模仿" adda"汽车和司机的行为,我可以传递任何一串'和' s。我们的想法是返回一个函数,然后在后面的列表中执行该函数。对此函数的调用可能如下所示:

((cxr" dd")'(1 2 3))

我已逐步建立到我认为它应该工作的位置,首先创建一个letrec,返回正确的car和cdr字符串。然后将letrec的主体移动到定义内的lambda主体。

(define (cxr cmdString)  ;named function to call
    (lambda (X)          ;beginning of un-named function to return
        (                   
            (cond
                ;if the string passed in is empty, return the arguments to the second function
                ((= 0 (string-length cmdString)) 'X)

                ;if its an 'a', add a call to car to the list and call the function again with a shorter command string.
                ((char=? #\a (string-ref cmdString 0)) (list (quote car) (cxr (substring cmdString 1 (string-length cmdString))))) 

                ;if its a 'd', add a call to cdr to the list and call the function again with a shorter command string.
                ((char=? #\d (string-ref cmdString 0)) (list (quote cdr) (cxr (substring cmdString 1 (string-length cmdString))))) 
            )
        )
    )
)

((cxr "a") '(1 2 3)) ;call the function

使用Repl.it,我收到一条对我来说毫无意义的错误消息。为了让它以不同的方式工作,我已经做了一点点,但我想知道我做错了什么。

我建立的Letrec,返回正确的汽车字符串和cdr:

(letrec
    (
        (cxr
            (lambda (cmdString)
                (cond
                    ((= 0 (string-length cmdString)) 'X)
                    ((char=? #\a (string-ref cmdString 0)) (list (quote car) (cxr (substring cmdString 1 (string-length cmdString)))))
                    ((char=? #\d (string-ref cmdString 0)) (list (quote cdr) (cxr (substring cmdString 1 (string-length cmdString)))))
                )
            )   
        )
    )
(cxr "daa") ;can change "daa" to any combination of 'd's and 'a's.
)

具有我寻求的行为的Finagled版本,没有经过良好测试(并且有点丑陋):

(define (cxr X)
(list 'lambda '(X) 
    (letrec
        (
            (computecxr
                (lambda (cmdString)
                    (cond
                        ((= 0 (string-length cmdString)) 'X)
                        ((char=? #\a (string-ref cmdString 0)) (list 'car (computecxr (substring cmdString 1 (string-length cmdString)))))
                        ((char=? #\d (string-ref cmdString 0)) (list 'cdr (computecxr (substring cmdString 1 (string-length cmdString)))))
                    )
                )   
            )
        )
        (computecxr X)
    )
)
)

(print (cxr "a"))
((eval (cxr "dd")) '(1 2 3))

任何建议都会有所帮助。谢谢。

编辑:亚历克西斯,我没有看到我的问题和另一个问题之间的相关性。我在我的程序中没有使用if,也不是我得到的错误。你能解释为什么你认为它是重复的吗?

3 个答案:

答案 0 :(得分:1)

在您的代码中,由于错误使用括号而导致语法错误的一部分,您正在尝试使用quotelist构建列表,然后必须评估< / em>得到结果。

但是如果你想探索函数式编程,你应该避免根据具体的数据结构来考虑函数,比如列表。相反,您应该开始将它们视为语言的 values ,就像整数和字符串一样,例如作为其他函数返回的函数,或者应用于其他表达式的表达式,因为它们评估为功能

以下是您的问题的可能解决方案,编写为高级函数,使用DrRacket进行测试:

(define (cxr cmd-string)
  (if (= 0 (string-length cmd-string))
      (lambda (x) x) 
      (let* ((first-char (string-ref cmd-string 0))
             (f (if (char=? first-char #\a) car cdr)))
        (lambda (x) (f ((cxr (substring cmd-string 1 (string-length cmd-string))) x))))))

((cxr "add") '(1 2 3)) ;  => 3

第一个测试检查字符串是否为空,在这种情况下返回标识函数(即返回其参数的函数)。

否则,字符串的第一个字符绑定到first-char,然后相应的函数绑定到f(注意carcdr是两个原语函数),最后返回的值是一个新函数,带有一个参数x,它将f应用于x函数的结果,该函数是cxr递归调用(define (mk-cxr cmd-string) (define (mk-body string) (if (= 0 (string-length string)) '(x) (let* ((first-char (string-ref string 0)) (operation (if (char=? first-char #\a) 'car 'cdr))) (list (cons operation (mk-body (substring string 1 (string-length string)))))))) (cons 'lambda (cons '(x) (mk-body cmd-string)))) (mk-cxr "add") ; => (lambda (x) (car (cdr (cdr x)))) 的结果1}}。

要查看函数方法和“build-a-list-represent-a-function”之间的区别,特别是递归的不同用法,请将上述函数与以下函数进行比较:

SSL

答案 1 :(得分:1)

原始访问器不会神奇地生成,但通常是作为组合的全局绑定。

但是可以这样做。一个名为public class InstantRequestHandler { public String sendGetRequest(String uri) { try { URL url = new URL(uri); HttpURLConnection con = (HttpURLConnection) url.openConnection(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(con.getInputStream())); String result; StringBuilder sb = new StringBuilder(); while((result = bufferedReader.readLine())!=null){ sb.append(result); } return sb.toString(); } catch (Exception e) { return null; } } public String sendPostRequest(String requestURL, HashMap<String, String> postDataParams) { URL url; String response = ""; try { url = new URL(requestURL); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setReadTimeout(15000); conn.setConnectTimeout(15000); conn.setRequestMethod("POST"); conn.setDoInput(true); conn.setDoOutput(true); OutputStream os = conn.getOutputStream(); BufferedWriter writer = new BufferedWriter( new OutputStreamWriter(os, "UTF-8")); writer.write(getPostDataString(postDataParams)); writer.flush(); writer.close(); os.close(); int responseCode = conn.getResponseCode(); if (responseCode == HttpsURLConnection.HTTP_OK) { BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream())); response = br.readLine(); } else { response = "Error Registering"; } } catch (Exception e) { e.printStackTrace(); } return response; } private String getPostDataString(HashMap<String, String> params) throws UnsupportedEncodingException { StringBuilder result = new StringBuilder(); boolean first = true; for (Map.Entry<String, String> entry : params.entrySet()) { if (first) first = false; else result.append("&"); result.append(URLEncoder.encode(entry.getKey(), "UTF-8")); result.append("="); result.append(URLEncoder.encode(entry.getValue(), "UTF-8")); } return result.toString(); } } 的常见程序通常是将程序链接在一起的东西,这就是这里发生的事情。通过撰写,compose并且不使用cxr非常简单。编译器几乎没有机会优化使用eval的代码,并且如果以某种方式证明代码具有来自用户输入的元素,则存在安全问题。

eval

答案 2 :(得分:1)

确定。让我们在您的问题中进行第一次尝试,并使用适当的缩进和正常的)展示位置进行清理:

(define (cxr cmdString) ; named function to call
  (lambda (X)           ; beginning of un-named function to return
    ((cond
       ; if the string passed in is empty, return the arguments to the second function
       [(= 0 (string-length cmdString)) 'X]

       ; if its an 'a', add a call to car to the list and call the function again with a shorter command string.
       [(char=? #\a (string-ref cmdString 0))
        (list (quote car) (cxr (substring cmdString 1 (string-length cmdString))))]

       ; if its a 'd', add a call to cdr to the list and call the function again with a shorter command string.
       [(char=? #\d (string-ref cmdString 0))
        (list (quote cdr) (cxr (substring cmdString 1 (string-length cmdString))))]))))

((cxr "a") '(1 2 3)) ; call the function

现在可以稍微轻松地看到问题了。第一个问题是一个简单的paren错误,你将lambda的主体包裹在一组不应该存在的括号中。请记住,在方案中,括号通常表示函数调用。这就是您收到application: not a procedure错误的原因。现在已修复:

(define (cxr cmdString) ; named function to call
  (lambda (X)           ; beginning of un-named function to return
    (cond
      ; if the string passed in is empty, return the arguments to the second function
      [(= 0 (string-length cmdString)) 'X]

      ; if its an 'a', add a call to car to the list and call the function again with a shorter command string.
      [(char=? #\a (string-ref cmdString 0))
       (list (quote car) (cxr (substring cmdString 1 (string-length cmdString))))]

      ; if its a 'd', add a call to cdr to the list and call the function again with a shorter command string.
      [(char=? #\d (string-ref cmdString 0))
       (list (quote cdr) (cxr (substring cmdString 1 (string-length cmdString))))])))

((cxr "a") '(1 2 3)) ; call the function

代码给出了结果:

'(car #<procedure>)

它返回一个包含两个元素的列表,相当于(list 'car #<procedure>)。这可能不是你的意思。我猜你想让它返回列表car的{​​{1}},即'(1 2 3)。首先,在评论中写下:

1

现在我们已经记录了;; cxr : CmdString -> (ConsTree -> Any) ;; Given a command string containing 'a' and 'd' characters, returns ;; a function that gets the corrosponding element in the cons tree. ;; For example, (cxr "a") should return a function equivalent to car, ;; (cxr "d") should return a function equivalent to cdr, and ;; (cxr "add") should return a function equivalent to caddr. 返回的内容,我们可以用它做点什么。我们可以在递归的情况下正确使用它。它返回一个接受cons树的函数,因此我们可以将它应用于(cxr ...),这是我们的cons树:X。这将返回((cxr ...) X)的子句,该子句对应于字符串的其余部分,X情况为(cddr X)。因此,您只需将"add"car应用于:

cdr

在上下文中:

; 'a' case
(car ((cxr ...) X))
; 'd' case
(cdr ((cxr ...) X))

现在这给出了这个错误:

(define (cxr cmdString) ; named function to call
  (lambda (X)           ; beginning of un-named function to return
    (cond
      ; if the string passed in is empty, return the arguments to the second function
      [(= 0 (string-length cmdString)) 'X]

      ; if its an 'a', call car on a recursive call using the rest of the command string.
      [(char=? #\a (string-ref cmdString 0))
       (car ((cxr (substring cmdString 1 (string-length cmdString))) X))]

      ; if its a 'd', call cdr on a recursive call using the rest of the command string.
      [(char=? #\d (string-ref cmdString 0))
       (cdr ((cxr (substring cmdString 1 (string-length cmdString))) X))])))

((cxr "a") '(1 2 3)) ; call the function

car: contract violation expected: pair? given: 'X 来自哪里?基本情况。我们也需要修复基本情况,但这很简单,只需使用'X代替X

'X

测试它:

;; cxr : CmdString -> (ConsTree -> Any)
;; Given a command string containing "a" and "d" characters, returns
;; a function that gets the corrosponding element in the cons tree.
;; For example, (cxr "a") should return a function equivalent to car,
;; (cxr "d") should return a function equivalent to cdr, and
;; (cxr "add") should return a function equivalent to caddr.
(define (cxr cmdString) ; named function to call
  (lambda (X)           ; beginning of un-named function to return
    (cond
      ; if the string passed in is empty, return the argument to the second function
      [(= 0 (string-length cmdString)) X]

      ; if its an 'a', call car on a recursive call using the rest of the command string.
      [(char=? #\a (string-ref cmdString 0))
       (car ((cxr (substring cmdString 1 (string-length cmdString))) X))]

      ; if its a 'd', call cdr on a recursive call using the rest of the command string.
      [(char=? #\d (string-ref cmdString 0))
       (cdr ((cxr (substring cmdString 1 (string-length cmdString))) X))])))

更新

本着@Sylwester > ((cxr "a") '(1 2 3)) 1 > ((cxr "d") '(1 2 3)) '(2 3) > ((cxr "add") '(1 2 3)) 3 > ((cxr "adda") '((1 2 3) 4)) 3 答案的精神,您可以将此代码翻译为使用compose而不是compose,同时保留原始版本的一些相同结构代码:

(lambda (X) ...)

如果你看一下这个结构,这与你原来写的不太一样。它没有lambda,因为它使用;; cxr : CmdString -> (ConsTree -> Any) ;; Given a command string containing "a" and "d" characters, returns ;; a function that gets the corrosponding element in the cons tree. ;; For example, (cxr "a") should return a function equivalent to car, ;; (cxr "d") should return a function equivalent to cdr, and ;; (cxr "add") should return a function equivalent to caddr. (define (cxr cmdString) (cond ; if the string passed in is empty, return the identity function. [(= 0 (string-length cmdString)) identity] ; if its an 'a', compose car with a recursive call using the rest of the command string. [(char=? #\a (string-ref cmdString 0)) (compose car (cxr (substring cmdString 1 (string-length cmdString))))] ; if its a 'd', compose cdr with a recursive call using the rest of the command string. [(char=? #\d (string-ref cmdString 0)) (compose cdr (cxr (substring cmdString 1 (string-length cmdString))))])) 构建函数,它返回基本案例的标识函数而不是符号compose,并且对于它使用的递归情况{{ 1}}您使用'Xcompose