Построитель функций в схеме - PullRequest
1 голос
/ 29 марта 2012

Функция, которую я должен построить, должна принимать список чисел в качестве параметра и выдавать одну функцию в качестве вывода, которое делает следующее: Если число в списке является положительным числом, добавьте его, если оно отрицательно, умножьте его, и если оно равно 0, возведите в квадрат число.

Например, если я передам (4 -1 0), он должен вернуть функцию, которая принимает один параметр, добавляет 4 к нему, умножает его на -1, возводит в квадрат и возвращает это.

Я думаю, что я на правильном пути, но меня это сильно смущает.Я не обязательно ищу решение, но любая помощь, полученная там, была бы удивительна.Вот что у меня есть:

(define (buildseries L)
  (define (a x) 
    (lambda (y) (+ x y)))
  (define (m x) 
    (lambda (y) (* x y)))
  (define (s x) 
    (lambda (x) (* x x)))
  (define (funcfind d)
    (cond
     [(null? d) (a 0)]
     [(> d 0) (a d)]
     [(= d 0) (s d)]
     [(< d 0) (m d)]))
  (funcfind (first L)))

((buildseries '(2)) 2)

Я не знаю, как создать функцию, которая состоит из других функций ... Просто ощущение, что здесь потеряно.

Ответы [ 3 ]

3 голосов
/ 29 марта 2012

Я думаю, вы довольно близки к решению. На вашем месте я бы определил еще две вспомогательные функции как внутренние определения buildseries. Одной из них будет identity функция, которая просто возвращает свой аргумент без изменений. Другой будет вспомогательная функция compose, которая принимает две функции f и g и возвращает новую функцию, которая вычисляет их композицию. Это будет выглядеть примерно так, как ваши a и m помощники, которые также являются "фабриками функций", возвращающими анонимную функцию, которая зависит от их аргумента. Вы можете подумать о переводе следующей математической нотации, используя . для представления композиции функций, в Scheme: (f . g)(x) = f(g(x)).

Кстати, я думаю, что ваше определение s не совсем верно: это не должна быть «фабрика функций», которая возвращает лямбда, а просто простая функция x. будет работать так, как написано, но поскольку вы ничего не делаете с (внешним) аргументом x, вы можете упростить его до (define (s x) (* x x)). Тогда в вашем (= d 0) случае вы можете просто вернуть s, что само по себе является очень хорошим значением функции.

Теперь вам нужно подумать о двух вещах. Во-первых, каков ваш базовый случай? Какую функцию вы возвращаете, когда список l пуст? Далее, когда l не пусто, как вы будете комбинировать все, что вы делаете с элементом first списка, с тем, что вы делаете, рекурсивно, с rest списка?

Надеюсь, это полезно. Дайте мне знать, если я смогу улучшить ответ!

1 голос
/ 29 марта 2012

во-первых, вам нужен примитив функции bulider, который принимает число и создает функцию соответствия:

(define (num->fun d)
  (cond [(> d 0) (lambda (x) (+ x d))]
        [(= d 0) (lambda (x) (* x x))]
        [(< d 0) (lambda (x) (* x d))]))

затем вы можете сопоставить эту функцию списку чисел, он возвращает список функций вбыть составленным:

> (map num->fun '(4 -1 0))
=>'(#<procedure> #<procedure> #<procedure>)

так что вы можете использовать функцию высокого порядка compose для составления этого списка функций:

(apply compose (reverse (list-of-functions)

будьте осторожны, compose составлять функции в обратном порядке, поэтому перед составлением обращайтесь к списку функций.Вы можете сделать это:

(define (buildseries L)
  (apply compose (reverse (map num->fun L))))
;try it:
((buildseries '(4 -1 0)) 1);=>25
1 голос
/ 29 марта 2012

Ответ Джона очень хорош.Вы должны попытаться реализовать это столько, сколько сможете.Если вам нужно, вы также можете обратиться к моему ответу здесь (который не соответствует подходу Джона, поскольку я написал большую часть своего ответа до того, как он опубликовал свой):

(define (fun nums)
  (lambda (x)
    (let loop ((nums nums)
               (value x))
      (if (null? nums) value
          (let ((num (car nums))
                (rest (cdr nums)))
            (cond ((positive? num)
                   (loop rest (+ value num)))
                  ((negative? num)
                   (loop rest (* value num)))
                  ((zero? num)
                   (loop rest (* value value)))))))))

Вам следует изучить его, чтобы понять, какэто работает, затем напишите свою собственную версию, используя совершенно другой подход, как идея Джона об использовании compose.: -)


Редактировать: написанную мной функцию можно еще больше упростить: с помощью SRFI 1 fold вы можете сделать это:

(define (fun nums)
  (define (step num value)
    (cond ((positive? num) (+ value num))
          ((negative? num) (* value num))
          (else (* value value))))
  (lambda (x)
    (fold step x nums)))
...