picolisp.ru
Переключить темный/светлый/авто режим Переключить темный/светлый/авто режим Переключить темный/светлый/авто режим Back to homepage

PicoLisp. Прагматичный язык программирования

Перевод. Оригинал здесь

Почему PicoLisp?

PicoLisp сильно отличается от других лиспов. Основная причина заключается в его ориентации на данные.

Большинство лиспов фокусируются на коде. Они подчеркивают функции и макросы так или иначе, а также эффективную компиляцию в машинный код. Это приводит к появлению множества различных типов данных, обрабатываемых неортогональными способами, часто с различными наборами функций. И результат компиляции (машинный код) больше не является Lisp и, таким образом, нарушает эквивалентность кода и данных.

В программировании конечной целью является манипулирование данными, а не функциями. Код и данные эквивалентны в Lisp, так что вы в любом случае получаете манипуляции с функциями бесплатно, но фокус должен быть на данных.

На уровне виртуальной машины PicoLisp имеет один-единственный тип данных: “cons-ячейка”.

На уровне языка он имеет только три типа данных: числа, символы и пары cons. Все они построены из ячеек.

То, что может показаться ограничением, на самом деле является большим преимуществом. Простая внутренняя структура обеспечивает высокую скорость запуска и выполнения. Ячейками можно свободно манипулировать любым мыслимым способом, предоставляя полный контроль программисту.

Символы являются “реальными” в PicoLisp. У них есть идентичность, физическое существование. Вы можете фактически захватить символ по его адресу и манипулировать его значением и свойствами (помните, что Lisp раньше был “языком манипулирования символами”).

Ортогональность языка позволяет создавать очень мощный и компактный код. Реализация данного алгоритма часто более выразительна и лаконична, чем в других лиспах.

Вся система открыта. Ничто не “скрыто за кулисами”. Внутреннее состояние может быть проверено (и понято!) в интерактивном режиме, вплоть до уровня ячейки и даже байта.

Интерпретатор PicoLisp реализован в самом PicoLisp. Он записан в подмножестве PicoLisp, которое - при выполнении - генерирует LLVM-IR (промежуточное представление), которое, в свою очередь, собирается LLVM для желаемой целевой архитектуры.

Помимо своего простого механизма, PicoLisp поддерживает пространства имен, сопрограммы, объектно-ориентированная база данных, веб-графический интерфейс, динамический собственные C-вызовы, встроенный редактор в стиле vi и может быть установлен в Android как приложение PilBox.

Таким образом, PicoLisp полезен для выполнения практической работы. С момента своего основания в 1988 году PicoLisp использовался в коммерческих проектах. Автор и его компания на протяжении многих лет выполняли все свои проекты исключительно в PicoLisp.

Несколько примеров

Факториал:

   : (de fact (N)
      (if (=0 N)
         1
         (* N (fact (dec N))) ) )
   -> fact

   : (fact 6)
   -> 720

Нерекурсивный факториал:

   : (apply * (range 1 6))
   -> 720
   : (apply * (range 1 40))
   -> 815915283247897734345611269596115894272000000000

Сопрограмма генератора Фибоначчи:

   : (co 'fibo
      (let (A 0  B 1)
         (loop
            (yield
               (swap 'B (+ (swap 'A B) B)) ) ) ) )
   -> 1
   : (co 'fibo T)
   -> 1
   $: (co 'fibo T)
   -> 2
   $: (co 'fibo T)
   -> 3
   $: (co 'fibo T)
   -> 5
   $: (co 'fibo T)
   -> 8

Скалярное произведение:

   : (sum * (1 2 3) (4 5 6))
   -> 32

Объединение списка из 4 байт в 32-разрядное число:

   : (sum >> (-24 -16 -8 0) (127 3 4 255))
   -> 2130904319
   : (hex @)
   -> "7F0304FF"

Объединение нескольких списков в один список:

   : (mapcan list '(a b c) (1 2 3) '(X Y Z))
   -> (a 1 X b 2 Y c 3 Z)

Группировка одинаковых символов независимо от регистра:

   : (by lowc group '(Abc dEf ghI DeF GHI abc))
   -> ((Abc abc) (dEf DeF) (ghI GHI))

Сортировка символов по длине имени:

   : (by length sort (all))
   -> (NIL ! $ % & * + - / : ; < = > ? @ A B C ...

В других лиспах and, or и т.д. являются макросами и, следовательно, не могут быть применены в функции apply. В PicoLisp они являются нормальными функциями:

   : (apply and (1 NIL 3))
   -> NIL
   : (apply and (1 2 3))
   -> 3
   : (mapcar and (1 NIL 3) (1 2 3))
   -> (1 NIL 3)
   : (mapcar or (1 NIL NIL) '(NIL 2 NIL) '(NIL NIL 3))
   -> (1 2 3)

Перечисление всех открытых файловых дескрипторов текущего процесса:

   : (dir (pack "/proc/" *Pid "/fd"))
   -> ("0" "1" "2" "3")  # "3" is from 'dir' itself

Вызов нативного кода для получения текущего имени пользователя:

: (%@ "getlogin" 'S)
-> "u0\_a353"