0

I am writing a function called ptyper that takes a nested list, nl. This function replaces all occurrences of a number with n and all occurrences of a symbol with s. This is what I have now:

(define (ptyper nl) (cond
((null? nl) '())
((list? nl)
 (let ((ls (car nl)))
  (list (ptyper ls))))
((number? (car nl))
 (cons "n" (cdr nl)))
((symbol? (car nl))
 (cons "s" (cdr nl)))
(else
 (cons (car nl) (cdr nl)))))

I ran this test (ptyper '(2 (abc () "abc"))) but received an error that their was a contract violation. I'm not exactly sure what I'm doing wrong so if could use some help. Thanks!

SarahCaw
  • 11
  • 2

2 Answers2

0

Here is a data definition for an S-expression, this models your data.

; An S-expr is one of: 
; – Atom
; – SL

; An SL is one of: 
; – '()
; – (cons S-expr SL)


; An Atom is one of: 
; – Number
; – String
; – Symbol

We have predicates for every kind of data except Atom, so we make atom?:

;; Any -> Boolean
;; is the x an atom?
(define (atom? x)
  (not (list? x)))

We follow the structure of the data to build "templates" for our functions:

(define (func sexp)
  (cond
    [(atom? sexp) (func-atom sexp)]
    [else (func-sl sexp)]))


(define (func-sl sl)
  (cond
    [(empty? sl) ...]
    [else (... (func (first sl)) ... (func-sl (rest sl)) ...)]))


(define (func-atom at)
  (cond
    [(number? at) ...]
    [(string? at) ...]
    [(symbol? at) ...]))

We fill in the gaps:

; Atom -> String
(define (subs-atom at)
    (cond
    [(number? at) "n"]
    [(string? at) at]
    [(symbol? at) "s"]))


; SL -> SL
(define (subs-sl sl)
  (cond
    [(empty? sl) sl]
    [else (cons (subs-sexp (first sl))
                (subs-sexp (rest sl)))]))

; S-exp -> S-exp
(define (subs-sexp sexp)
  (cond
    [(atom? sexp) (subs-atom sexp)]
    [else (subs-sl sexp)]))

Using the interface for ptyper:

(define (ptyper nl)
  (subs-sexp nl))

(ptyper '(2 (abc () "abc")))
; => '("n" ("s" () "abc"))
Atharva Shukla
  • 2,098
  • 8
  • 21
0

Here is a possible solution with one function:

(define (ptyper nl)
  (cond
    ((null? nl) '())      ; if the argument is an empty list, return the empty list
    ((list? nl)           ; if the argument is a list, then
     (let* ((c (car nl))  ; get its first element
            (nc (cond ((number? c) "n") ; transform it for numbers
                      ((symbol? c) "s") ; and symbols
                      ((list? c) (ptyper c)) ; if a list recur over it
                      (else c))))       ; otherwise (e.g. a string) return as it is
       (cons nc (ptyper (cdr nl)))))    ; recursive call on the rest of the list
    (else nl)))  ; this should never happen for the specification,
                 ; return the parameter or cause an error

Note that the error in your case is caused by the recursive call. When the function is called on an atom, for instance 2, first it checks for null and list?, and those checks returns false. Then it checks for (number (car nl)), but nl is equal to 2 and so car fails.

Renzo
  • 26,848
  • 5
  • 49
  • 61