Functional programming in LISP

走远了吗. 提交于 2019-12-26 03:09:44

问题


i just have started to learn function programming and it is a bit confusing for me, i have a task now: remove all duplicates from the row with lists, so: input row:

(SETQ X (LIST  2 -3 (LIST 4 3 0 2) (LIST 4 -4) (LIST 2 (LIST 2 0 2))-3)) 

I want output be like this : (2 -3 (4 3 0)(-4)()) I want to make it with recursion. I have some conceptual questions: how can i remove an element from list or i should make a new one for output? In other programming languages every step of recursion has it own scope for variables, is it same here? Please, can you describe the way, how would you do this?

Btw, i am trying to run this code:

(SETQ X (LIST  2 -3 (LIST 4 3 0 2) (LIST 4 -4) (LIST 2 (LIST 2 0 2))-3))(DEFUN SEARCHDEEP (WHAT WHERE)
(COND
    ((NULL WHERE) NIL)
    (T (OR 
            (COND 
                ((ATOM (CAR WHERE)) (EQUAL WHAT (CAR WHERE)))
                (T (SEARCHDEEP WHAT  (CAR WHERE)))
            )
            (SEARCHDEEP WHAT (CDR WHERE))
        )
    )
))

(DEFUN REMDOUBLES (INPUT OUTPUT)(
(COND 
    ((NULL INPUT) NILL)
    (T 
        (REMDOUBLES (CDR INPUT) OUTPUT)
        (PRINT INPUT)
    )
)))


(REMDOUBLES X NIL)

But i am getting this error, what does it mean?

SYSTEM::%EXPAND-FORM: (COND ((NULL INPUT) NILL) (T (REMDOUBLES (CDR INPUT) OUTPUT) (PRINT INPUT))) should be a lambda expression


回答1:


In functional programming you don't remove elements from the arguments so you most definitely will make a new list, however in many cases you can share structure (tails) that are the same in the argument and the result.

Common Lisp is lexically scoped. That means that free variables that existed when the function was created plus the global scope is known in addition to bound variables, which would be bound unqiuely for each use just like the other languages you might know.

"something should be a lambda expression" is a Common Lisp error when you try to have an expression in operator position. eg. the Scheme code ((if (< x 10) + -) 5 10) becomes either 15 or -5 based on what function the expression in operand position evaluates to. In Common lisp you can either have a symbol, eg. like + in (+ 1 2) or a lambda eg. ((lambda (x) (* x x)) 10). You tried ((cond ...)) which would work in Scheme but not in Common Lisp. In Common Lisp you need to do (funcall (if (< x 10) #'+ #'-) 5 10). Since the parentheses are almost put as curlies in C# I guess they are misplaced just as if someone would add a esxtra set of () in the end of a statement someFun(arg)() when someFun doesn't return a function.

I would have solved your code like this:

;; setq is for mutating, defparameter is a good option to make a global variable 
(defparameter *test* '(2 -3 (4 3 0 2) (4 -4) (2 (2 0 2)) -3))

(defun unique-elements (lst)
  (let ((h (make-hash-table :test 'equal)))
    (labels ((aux (lst)
               (cond ((null lst) '())
                     ((consp (car lst))
                      (let ((a (aux (car lst))))
                        (if (null a)
                            (aux (cdr lst)) ; don't include empty elements
                            (cons a (aux (cdr lst))))))
                     ((gethash (car lst) h)
                      (aux (cdr lst)))
                     (t (setf (gethash (car lst) h) t)
                        (cons (car lst) (aux (cdr lst)))))))
      (aux lst))))

(unique-elements *test*) ; ==> (2 -3 (4 3 0) (-4))



回答2:


I don't know Common Lisp but I came up with a solution for you that uses racket. Converting this to Lisp should be trivial, but I'll leave that as a task for you. Since this is probably a homework assignment anyway, it will be good for you to work thru the code and understand it.

The only racket-specific thing I think I'm using is racket's mutable-set, which is just used to keep track of unique values as we add them to the output. The set is discarded after the procedure's computation is complete.

#lang racket

(define input (list  2 -3 (list 4 3 0 2) (list 4 -4) (list 2 (list 2 0 2)) -3))

(define (procedure xs)
  (define (aux acc s xs)
    (cond [(empty? xs) (reverse acc)]
          [(list? (car xs)) (aux (cons (aux empty s (car xs)) acc) s (cdr xs))]
          [(set-member? s (car xs)) (aux acc s (cdr xs))]
          [else (begin (set-add! s (car xs))
                       (aux (cons (car xs) acc) s (cdr xs)))]))
  (aux empty (mutable-set) xs))

(define output (my-procedure input))

(display output)
; => (2 -3 (4 3 0) (-4) (()))

It's a little complicated because it's mixing tree recursion, folding, and unique filtering all in one procedure. A better solution would separate those processes into generic procedures and then compose them together in a more declarative final procedure that does your intended task.



来源:https://stackoverflow.com/questions/39808344/functional-programming-in-lisp

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!