Здесь необходимо выполнить два вида перевода:
От префиксной записи (функция предшествует аргументам) к инфиксной / постфиксной записи (метод между объектом и параметрами).
От функционального (функция и данные не связаны жестко) к объектно-ориентированному (методы привязаны к объектам).
Я буду использовать точечную запись вScala, чтобы прояснить ситуацию.
Итак, в Лиспе есть (function arguments)
, поэтому довольно легко определить, каковы аргументы каждой функции.В Scala у вас есть object.method(parameters)
, поэтому давайте пройдемся по каждой функции Lisp, чтобы определить, что это за аргументы и что это за объект.
С другой стороны, некоторые функции Lisp будут выполнять некоторые операции с каждым полученным аргументом., что не означает, как работают методы Scala.В этих случаях нужно будет ввести дополнительные методы перевода, чаще всего это последовательность map
.
CDR
Как вы упоминали, это Scala'stail
.Увы, tail
- это метод без параметров, а cdr
также получает только один параметр, поэтому нет необходимости в дальнейшем переводе.Следовательно,
(cdr (map (lambda (x) (* x x)) somelist))
становится частично переведенным
(map (lambda (x) (* x x)) somelist ).tail
MAP
В приведенном примере отсутствует аргумент, которыйтип результата.Итак, давайте предположим, что там был 'list
.Перевод здесь более сложный, потому что map
в Scala - это метод для коллекции, а не для функции.Таким образом, somelist
является объектом, а (lambda (x) (* x x))
параметром метода.
Таким образом, перевод из частично переведенного
(map (lambda (x) (* x x)) somelist).tail
в еще частично переведенный
somelist.map(lambda (x) (* x x)).tail
LAMBDA
Этот способ более сложный, поскольку в Scala нет метода, который является его эквивалентом, и не может быть, как нетМетод сможет связывать переменные.Тем не менее, lambda
присущ языку со следующим синтаксисом:
(argument list) => expression
Следовательно,
(lambda (x) (* x x))
переводит (частично) в
((x) => (* x x))
Возвращаясь к примеру, у нас
somelist.map(lambda (x) (* x x)).tail
становится
somelist.map((x) => (* x x)).tail
Здесь есть два важных момента.Во-первых, Lisp динамически типизирован, поэтому нет необходимости объявлять тип x
.Это не относится к Scala, которая может усложнить задачу, поскольку не существует общего типа для всех чисел.
Второй момент, однако, заключается в том, что Scala имеет вывод типа , поэтомуон может вывести тип x
из типа somelist
, что делает приведенный выше спорный пункт в данном конкретном случае .
Наконец,
*
Что часто бывает сложнее, поскольку действительно применимо ко всем имеющимся у вас аргументам.Обычный перевод
(* arguments)
- это
collection.reduceLeft((x, y) => x * y)
, где collection
- это некая коллекция, содержащая все arguments
.
. В этом случаеоднако, есть ровно два аргумента, поэтому он может быть переведен на собственный *
в Scala.Итак, для заключительной части перевода мы берем
somelist.map((x) => (* x x)).tail
и превращаем его в
somelist.map((x) => x * x).tail
Надеюсь, где-то на пути был ответ на ваши сомнения.