Русский
Русский
English
Статистика
Реклама

Lisp

Как я устал от JavaScript и создал свой собственный язык программирования

10.11.2020 14:15:42 | Автор: admin

За свою карьеру я успел поработать со множеством языков программирования. Писал flash-игры на ActionScript 3 и Android-игры на Java, сервера на Java, Scala и NodeJS (JavaScript), скрипты на Python, веб и мобильные приложения на React (JavaScript). И на каком бы языке я не писал, меня не покидало ощущение, что синтаксис этого языка слишком многословен, полон излишеств, шума и синтаксического бойлерплейта, мешающего пониманию написанного кода.

Уже тогда я начал делать первые попытки создать свой собственный язык программирования, лишенный этих недостатков. Но для начала мне надо было определиться с тем, что именно не так с существующими языками и каким образом можно формализовать параметры "качества" языка, чтобы начать их улучшать. После долгих размышлений и сравнений я выработал для себя несколько параметров:

  • Человекочитаемость - идеальный язык должен быть читабельным и легким для понимания человеком

  • Лаконичность - код на идеальном языке программирования должен содержать как можно больше смысла на квадратный сантиметр экрана. Максимум семантики, минимум синтаксиса.

  • Внутренняя непротиворечивость - синтаксические конструкции языка должны быть внутренне согласованы и хорошо сочетаемы

  • Чистота и красота - язык должен выглядеть максимально чисто и эстетически красиво

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

Единственным параметром, которому не до конца соответствовал Lisp, был параметр чистоты и красоты. Уходящие за горизонт заборы из скобочек не нравились мне с точки зрения эстетики. И я нашел решение: чтобы уменьшить количество скобочек можно сделать значимой индентацию, как это сделано в Python.

Я продолжал заниматься своими экспериментами в приватном репозитории гитхаба, то забрасывая их, то снова к ним возвращаясь. А тем временем моим основным рабочим языком становился JavaScript.

Как я перестал бояться и полюбил JavaScript

Изначально я не любил JavaScript. Не потому что в нем было что-то не так, а просто потому что я подвергся влиянию популярного мнения, что JavaScript - это неполноценный язык для дурачков, а настоящие программисты пишут только на "тру" языках.

Незадолго до знакомства с JavaScript моим основным рабочим языком была Scala. Вот он-то мне казался по-настоящему крутым, ибо он был полон сверхсложной эквилибристки типов и даже для написания простейшего http-сервера на Scala требовался высший пилотаж.

Поэтому когда я открыл для себя NodeJS, я сначала не поверил, что можно писать так просто и лаконично. И чем дольше я знакомился с JavaScript, тем более гениально спроектированным и внутренне согласованным он мне казался. Система объектов и прототипов позволяет легко писать код в объектно-ориентированном стиле, а то, что в основе всего этого лежит функция, делает легким и приятным программирование в привычном мне функциональном стиле. А динамическая природа языка делает его фантастически гибким.

Кроме того в экосистеме JavaScript меня поразило обилие инструментов и хороших библиотек. В Scala в порядке вещей была ситуация, когда библиотека была написана для работы над PhD и заброшена после защиты диссертации. В Java библиотеки были в основном рабочими, но многие из них были абсолютно не дружелюбными - лежали не пойми где, не имели документации в нормальном виде, имели ужасный API и так далее. У каждого языка была своя ужасающая система сборки и управления зависимостями вроде maven, gradle или sbt.

В JavaScript же программисту доступен удобный пакетный-менеджер npm, полный прекрасно отлаженных библиотек с хорошей документацией, удобным API и дружелюбным коммьюнити. То, что кажется обыденностью в экосистеме JavaScript, в экосистемах других языков не является таковым: например, не во всех случаях является возможным понять что же делает какая-нибудь Ruby-библиотека по ее readme в гитхабе.

Отдельным преимуществом JavaScript является то, что сейчас его можно запустить где угодно. Для веб-приложений уже давно стандартом является React, на мобильных девайсах очень распространен React Native, на сервере бешено популярен NodeJS. JavaScript стал де-факто универсальным языком, на котором можно писать под что-угодно. Даже миллиарды микроволновок и утюгов, которые раньше были вотчиной Java, скоро все будут программироваться на JavaScript.

Но есть ли у JS какие-нибудь минусы?

Что не так с JavaScript

Я программирую на JavaScript, в основном, в чисто функциональном стиле. Я использую const, не мутирую объекты и массивы, использую чистые функции. Так что мой код выглядит примерно так:

const incrementNumbers = numbers => numbers.map(number => number + 1)const takeNumbersGreaterThan = threshold => numbers => numbers.filter(number => number > threshold)const func = (numbers, threshold) => {    const incrementedNumbers = incrementNumbers(numbers)    const filteredNumbers = takeNumbersGreaterThan(threshold)(incrementedNumbers)    return incrementedNumbers}

Не смотрите, что этот код является переусложенным и может быть написан в разы проще. Здесь я хочу продемонстрировать то, что если вы как и я пишите код на JavaScript в исключительно функциональном стиле, то кучу места на вашем экране занимает абсолютно ненужный вам синтаксический мусор вроде слова "const", когда все и так всегда константа, и фигурных скобочек, когда все и так разделено индентацией.

Собственно, именно эти недостатки и натолкнули меня на возвращение к проекту собственного языка программирования. Ну а из-за описанных мною ранее громадных преимуществ экосистемы именно JavaScript я сделал платформой для своего языка.

Это было долгое вступление, но давайте уже начнем знакомство с языком. Представляю вам мой уникальный, универсальный и унифицированный язык программирования Una.

Порядок выполнения операций

Давайте начнем с азов. А именно порядка выполнения операций. Как я писал выше, основой синтаксиса для моего языка послужил Lisp, но чтобы сократить количество скобочек, я решил использовать индентацию.

Поэтому в моем языке выражение:

a (b c) (d e)

можно также записать как:

a  b c  d e

Ну а выражение:

a (b (c d))

может быть записано так:

a  b (c d)

или так:

a  b    c d

Присваивание

Самый базовый оператор в любом языке программирования - это оператор присваивания. В случае функциональных иммутабельных языков программирования правильнее было бы сказать не присваивание, а объявление константы.

В Una константа объявляется так:

= name "John"= number 1

Если мы хотим присвоить константе значение вычислений, то делаем так:

= z (calculate x y)

а можно обойтись и без скобок, этот оператор позволяет сделать так:

= z calculate x y

или так

= z calclulate  x  y

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

Арифметика, сравнения и логика

В Una вы можете пользоваться стандартными JavaScript операторами арифметики, сравнения и логики.

Арифметические операции выглядят так:

= a (+ 1 2)= b (- 2 1)= c (* 3 2)= d (/ 4 2)= e (% 5 2)

Все из них могут принимать множество параметров. Например:

= sum (+ 1 2 3 4 5)

А минус может принимать и один параметр, что является отрицанием числа:

= a (- 1)= b -1

Вот пример сложных арифметических расчетов:

= a +  * 2 4  / 9 3  + (* 3 2) (/ 4 2)  *    + 1 2    / 6 3

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

= randomNumber Math.random ()

Операторы сравнения имеют некоторые отличия от JavaScript. Давайте посмотрим:

= a (== 1 1)= b (~= 1 '1')= c (!= 1 '1')= d (!~= 1 '2')= e (> 2 1)= f (>= 2 1)= g (< 1 2)= h (<= 1 2)

Оператор == и != - это точное по типу сравнение, аналог === и !== в JavaScript. Для неточного по типу сравнения нужно применять ~= и !~=.

Логические операторы тоже немного отличаются:

= a (& true false)= b (| true false)= c (! true)= d !c

Как вы видите, вместо && используется &, а вместо || используется |.

Условные операторы

Тернарный условный оператор работает также как и в JavaScript:

= message  ? (> 2 1) "Greater" "Less"

А еще существует условный оператор с возвращением значения:

?! (== number 1) "One"

Он используется в функцях и других вычислимых блоках, чтобы вернуть значение по условию и соответствует следующему коду на JavaScript:

if (number === 1) return "One"

Коллекции

В Una есть две базовые коллекции: массивы и объекты.

Массив задается следующим образом:

= numbers :: 1 2 3 4 5

А объект задается так:

= user :  name 'John'  age 13  passport :    id 1    country 'USA'

В Una работают все трюки JavaScript.

Можно задать элемент массива или поле объекта готовой константой:

= a 1= numbers :: a 2 3= name 'John'= user :  name  age 13

Работает троеточие:

= threeNumbers :: 1 2 3= fiveNumbers :: ...threeNumbers 45= userFields :  name 'John'  age 13= user :  id 1  gender 'm'  isAlive true  ...userFields

Работает деконструкция:

= numbers :: 1 2 3= (:: one two three) numbersconsole.log one= user : (name 'John') (age 12)= (: name) userconsole.log name

А чтобы взять определенный элемент массива или значение определенного поля объекта используется точка:

= list :: 1 2 3= object : (a 1) (b 2)console.log (. list 0)console.log (. object 'a')

Также точка может быть использована, чтобы взять конкретное поле объекта таким образом:

= object : (a 1)console.log (.a object)

Этот синтаксис удобен для вызова функций, лежащих внутри объекта.

Но давайте пойдем дальше и рассмотрим самую крутую фишку языка - стрелочные симметрии.

Стрелочная симметрия синхронных вычислений

Правая стрелка симметрии синхронных вычислений является функцией:

= sum -> (x y)  + x y= onePlusTwo -> ()  = one 1  = two 2  + one two

Последняя строчка функции всегда является возвращаемым значением. Данный код на JavaScript будет выглядить так:

const sum = (x, y) => x + yconst onePlusTwo = () => {  const one = 1  const two = 2  return one + two}

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

= isSumGreaterThanFiveIfXisNotZero -> (x y)  ?! (== x 0) "X is zero"  = sum (+ x y)  ? (> sum 5)    "Greater"    "Less"

Левая стрелка симметрии синхронных вычислений является мнгновенно выполняемым блоком кода, также называемым Immediately Invoked Function Expression:

= result <-  = a 1  = b 2  + a b

Этот оператор можно использовать для чего-то вроде задания константы значением по каким-то условиям:

= result <-  ?! (== value 0) "Zero"  ?! (== value 1) "One"  ? (< value 10) "Less than ten" "More than ten"

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

= func -> number  ? (== number 0)    <-      console.log "Number is zero!"  + number 1

Стрелочная симметрия асинхронных вычислений

Правой стрелкой симметрии асинхронных вычислений является асинхронная функция:

= getUserPosts --> user  database.loadPosts user.postIds

Левой стрелкой симметрии асинхронных вычислений является await:

= checkIfUserIsAdmin --> userId  = user <-- (database.loadUser userId)  == user.role 'admin'

Стрелочная симметрия модулей

Правой стрелкой модульной симметрии является импорт:

=-> './index.css'=-> 'react' React=-> './validation' (: validateEmail)

Он превращается в import или в require в зависимости от соответствующей настройки компилятора.

Левой стрелкой модульной симметрии является экспорт.

Дефолтный - export default в JavaScript:

<-= a

Экспорт отдельной константы export const в JavaScript:

<-= = a 1

Экспорт нескольких констант - export {a, b} в JavaScript:

<-= ()  a  b

Вы можете импортировать любые JavaScript-модули в Una, и любые Una-модули в JavaScript. Все модули полностью совместимы друг с другом.

Стрелочная симметрия ошибок

Правой стрелкой симметрии ошибок является try-catch:

|->  <-    = getName null    getName ()  -> error    console.log error    'John'

В отличие от JavaScript в Una этот оператор является выражением, всегда возвращающим значение, а также этот оператор не имеет блока finally.

Если нужно исполнить асинхронный код, то соответствующие стрелки симметрии заменяются на асинхронные:

|->  <--    getNameAsync ()  --> error    console.log error    "John"

Левой стрелкой симметрии ошибок является выброс ошибки:

= addOneToNumber -> number  ?! (isNaN number)    <-| "number is not valid"  + number 1

Стрелочная симметрия чейнинга

Правая стрелка симметрии чейнинга подставляет выражение как последний параметр следующей за ним функции. Это нужно для удобной работы с такими библиотеками как ramda:

=-> 'ramda' R= electronics ::  :    title ' iPhone '    type 'phone'= phones |>  electronics  R.find    R.propEq 'type' 'phone'  R.prop 'title'  R.toUpper  R.trim

Левая стрелка симметрии чейнинга подставляет выражение как первый параметр следующей за ним функции. Это удобно для работу со стандартными методами массивов и lodash:

= sum <| (:: 1 2 3)  .map (-> x (+ x 1))  .filter (-> x (> x 2))  .reduce (-> (x y) (+ x y)) 0

Без чейнинга это выражение выглядело бы уродски:

= sum .reduce  .filter    .map (:: 1 2 3) (-> x (+ x 1))    -> x (> x 2)  -> (x y) (+ x y)  0

Интерполяция строк

Одной из самых популярных возможностей современный языков программирования является интерполяция строк. В Una она выглядит не так красиво как в JavaScript, но все же пользоваться ею очень удобно:

= name 'John'= count 5= fruit 'apples'= text `  'Hello, ${0}' name  'I have ${0} ${1}'    count    fruitconsole.log text

Этот пример выведет:

Hello, JohnI have 5 apples

Так же вы можете провести интерполяцию строк по какой-либо функции - чтобы сделать это пришлите функцию первым параметром. Это очень часто используется например в styled-components:

= color 'red'= Container `  styled.div  'background-color: ${0};' color

React и React Native

Для написания веб-приложения на React или мобильного приложения на React Native вы не сможете использовать JSX. Вместо этого вы можете использовать функцию createElement, лежащую в основе React.

=-> './index.css'=-> 'react' React=-> 'react-dom' ReactDOM=-> './styles' S= (: (createElement e)) React= App -> ((: name))  = (:: count setCount) (React.useState 0)  e S.Container :    e S.Hello (: (color 'green')) 'Hello, '    e S.Name : name    e S.IncrementCount      : (onClick (-> () (setCount (+ count 1))))      'Press me'    e S.Count : countReactDOM.render  e App (: (name 'John'))  document.getElementById 'root'

Первым аргументом функция всегда принимает компонент, вторым объект с параметрами (для пустого объекта в Una вы можете использовать : ), а все последующие параметры - это chilldren.

Что еще предстоит сделать

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

  • регулярные выражения

  • возможность заинстансить класс (оператор new)

  • комментарии в коде

  • плагин для Visual Studio Code с подсветкой синтаксиса

  • и многое другое...

Заключение

Язык Una устанавливается в любой JavaScript-проект простейшим babel-плагином, который компилирует все файлы с расширением .una в JavaScript. Вы можете найти инструкции по установке, подробную документацию и примеры в моем репозитории на гитхабе. Я буду жутко рад, если вы поиграетесь с языком, протестируете его и дадите фидбек, что можно было бы улучшить, а что стоит починить. Ну и от звездочек конечно не откажусь.

Спасибо за внимание!

Подробнее..

SRFI-213 Поддержка курса SICP. Обсудим?

05.11.2020 14:15:50 | Автор: admin

TL;DR: Я написал и выложил на всеобщее обсуждение Scheme Request for Implementation 216. Он нацелен на то, чтобы одна из самых известных в мире учебных программ по Computer Science, Structure and Interpretation of Computer Programs, стала выполнимой в полном объёме не только на MIT/GNU Scheme, но и на других интерпретаторах и компиляторах, в частности, на вашем любимом. И если раньше запрос в багтрекер "сделайте, пожалуйста, поддержку SICP" звучал бы расплывчато, то после принятия данного SRFI, поддержка SICP должна стать намного более общепринятой.

Чтобы написать этот документ, я проработал SICP целиком (что потребовало более 700 рабочих часов и заслуживает отдельного поста), выделил части, до сих пор не вошедшие в стандарт, и сформулировал их в качестве двух документов, SRFI-203 (принят в сентябе 2020), и данного, SRFI-216, к которому я и приглашаю всех присоединиться.

За техническими деталями и подробностями, прошу под кат.

Что такое "Структура и Интерпретация Компьютерных Программ"? (Structure and Interpretation of Computer Programs)

Это одна из самых известных учебных программ по "общему программированию", ранее преподаваемая в Массачусеттском Технологическом Институте (MIT), в качестве вступительной, а ныне перенесённая на старшие курсы из-за гигантского объёма и глубины, которая, как считается более программисту не требуется. Курс проводит студента от однострочной программы, которая складывает два числа, до написания собственной реализации Scheme, включающей компилятор и интерпретатор. Первое издание книги, в которой изложена программа, было выпущено в 80е годы, второе вышло в 1996 году. В книге более 350 задач. Существует русский перевод. Книга была одной из первых, к которым стал прилагаться веб-сайт. (Который работает до сих пор.)

Чем она хороша?

Эта программа, как будто бы, ставит перед собой две цели. Одна -- это построить мостик через пропасть абстракции, зияющую между "вычислениями на базовых вычислительных элементах", таких, как сумматор и ячейка памяти, и высокоуровневыми абстракциями вида "если слово отсутствует в словаре, подчеркни его красным". Вторая -- это познакомить программиста с наиболее важными программными архитектурами, разработанных инженерами за много лет.

Чем она не устраивает сейчас?

За исключением двух программных систем, (MIT/GNU Scheme и Racket, из которых только одна (MIT) является Scheme-системой в полном смысле этого слова) SICP непроходима на большинстве Схем, которые встречаются в живой природе. Представьте, что книжка, "Язык Си" позволяла бы вам выучить только Intel C.

Вернее, для человека, который умудрился пройти в SICP достаточно далеко, слово "непроходима" является скорее вызовом, чем препятствием, однако задачи, требующие отсутствующего функционала, встречаются в программе раньше, чем приходит ощущение всемогущества.

Зачем проходить SICP на других Scheme-системах?

Одно из главных достоинств SICP -- это то, что он рассказывает, как построить "систему искусственного интеллекта" (в данном случае под ней понимается язык программирования высокого уровня) на практически любом Тьюринг-полном субстрате. Но тем более обидно осознавать, что проработать её в полной мере можно исключительно на двух программных системах, одна из которых не поддерживает Windows (MIT, по крайней мере, официально), а вторая вообще заявляет, что не является Scheme.

К тому же, основная сила Scheme в наши дни -- это не сила языка общего назначения ( программы общего назначения тоже получаются отличные, а компания Cisco до сих пор поддерживает собственный оптимизирующий интерпретатор), а возможность встраивания его как языка расширения в практически любой программный продукт, написанный на любом языке. Есть Схемы, работающие на JVM, CLR, Fortran, JavaScript. Схема является языком написания расширений расширения таких проектов как GNU Debugger, GNU GIMP и GNU Guix.

Для заинтересовавшегося программиста логичнее осваивать SICP на той Scheme, которая лучше всего встраивается в ту инфраструктуру, к которой он привык.

На реализацию этой цели и направлен данный SRFI.

Что же делать?

Поскольку автор сих строк всё-таки приобрёл (ложное) ощущение всемогущества, он решил поставить пару бетонных опор для того мостика, о котором говорилось несколькими абзацами выше. Конкретно это выразилось в написании документа Scheme Request For Implementation, под номером 216, в котором собран список требований, которым должен удовлетворять интерпретатор Scheme для того, чтобы на нём запускался полный набор примеров программного кода из SICP.

Конечно, сам факт наличия документа ещё ничего не гарантирует, необходимо, чтобы функционал был реализован в программных системах, однако документ сопровождается "возможной реализацией", которая работает как минимум на одной программной системе, отсутствующей в списке выше (Chibi-Scheme).

Что входит в SRFI-216?

Функционал, требуемый для прохождение SICP, но не общепринятый.

Случайные числа.

Предлагается функция (random x), которая генерирует случайное целое число меньше заданного. В связи с тем, что Схема спроектированна так, чтобы работать в том числе на CPU, не имеющих ни доступа к часам, ни источника энтропии, средства для работы со случайными числами не входят в стандарт R7RS-small. (Но будут входить в -large, вероятно.)

Доступ к дате и времени.

Предлагается функция (runtime), возвращающая значение текущего времени. По причинам, эквивалентным указанным выше, функционал для работы с датой также не входила в базовый стандарт в течение долгого времени, а когда был принят, имена функций не совпадали с таковыми из 1996 года.

Булевы значения.

В связи с тем, что Схема очень старый язык, работа с логическими выражениями была в разных реализациях осуществлена по-разному. Например, в каких-то реализациях символ #f, существует, а в каких-то нет. Также, во некоторых системах, по традиции LISP, пустой список также является "ложным" значением.

Для большей абстракции, таким образом, SICP нигде не использует ложное выражение само по себе, а пользуется переменными/константами true и false, которые гарантированно имеют, соответственно, верное значение, и ложное значение.

Эти две константы также реализуются в данном документе.

Многопоточное программирование.

Вопрос многопоточного программирования был крайне популярен в те годы, когда выпускался из института (десять лет назад), и хотя некоторый прогресс заметен, до сих пор нельзя сказать, что какая-то конкретная модель мультитрединга победила все остальные.

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

SICP, соответственно, требует существование двух примитивов, parallel-execute и test-and-set!, которые ровно эти две концепции и призваны прояснить.

Сама же по себе многопоточная модель Scheme сходна с таковой в Java.

Streams.

"Стримы" -- это бесконечные структуры данных, схожие с генераторами/итераторами в языке Python (или использовавшимся ранее xrange), только несравнимо более гибкие.

В принципе, они реализуемы в текущем стандарте, и не должны бы попадать в данный документ, однако, реализация базового примитива cons-stream, не может быть функцией, потому что не вычисляет свой второй аргумент. Про встроенные механизмы же синтаксического расширения SICP не говорит ничего.

Соответственно, эта структура также реализуется в данном proposal.

Что насчёт графики?

Работа с графикой не затрагивается в данном документе. Возможные примитивы опубликованы в SRFI-203.

Чем я могу помочь?

Во-первых, существование качественных стандартов невозможно без изучения их большим количеством людей. Очень нужны ревью предложения и кода.

Если у вас уже есть любимая реализация Scheme, поинтересуйтесь у людей, которые за неё отвечают, возможна ли реализация данного стандарта в вашей любимой системе.

Расскажите своим друзьям, студентам и энтузиастам, о том, что учиться по SICP не обязательно должно быть процессом, полным боли.

Если вы преподаёте программирование, или функциональное программирование, или у вас есть знакомые преподаватели, предложите им взглянуть на предлагаемое расширение, их фидбек будет в высшей степени ценным.

Ну, и надо сказать, что я просто считаю Схему отличным языком. Пользуйтесь Схемой, это можно делать на громадном количестве платформ, включая Plan9, Android, WebAssembly, и встраивать в другие программы.

Как именно можно присоединиться к обсуждению, можно найти по ссылке: https://srfi.schemers.org/srfi-216/

Контакты

Если вам показался этот пост полезным, на мои заметки можно подписаться, или задонатить без подписки:

Подробнее..

Опубликован Scheme Request For Implementation 203 A Simple Drawing Language in the Style of SICP

18.09.2020 18:11:01 | Автор: admin
Функциональная геометрияФункциональная геометрия

SICP

Обложка SICPОбложка SICP

Structure and Interpretation of Computer Programs -- это один из самых известных учебников программирования в мире, на основе которого несколько десятков лет преподавался начальный курс программирования в MIT, а во многих унивеситетах, в том числе в Беркли, преподаётся до сих пор.

SICP использует Scheme в качестве основного (практически единственного) языка программирования. Тем не менее, нельзя сказать, что это учебник Scheme, потому что он выходит далеко за пределы того, что обычно входит в программу "изучения языка". Стоит только упомянуть, что в программу входят системы распространения ограничений, интерпретаторы языков программирования, симуляторы цифровых схем, а также симулятор целого процессорного модуля.

Большая часть тем, входящих в учебник, выполнимы на "стандартной" (в смысле, соответствующего последнему на текущий момент стандарту Revised^7 Report on Algorithmic Language Scheme) Scheme.

Особенные темы

Цифовой сумматор, реализуемый в качестве одного из упражений SICPЦифовой сумматор, реализуемый в качестве одного из упражений SICP

Однако, для нескольких тем, встроенных средств языке недостаточно. В частности, темы случайных чисел, измерения времени выполнения, многопоточности и графического вывода стандартом языка не рассматриваются.

Принятая по-умолчанию в учебнике реализация MIT/GNU-Scheme содержит необходимые примитивы, расширяющие базовый язык так, чтобы курс становился проходим.

За многие годы, прошедшие с момента выхода SICP, некоторые реализации Scheme также реализовали многие примитивы, требуемые для прохождения курса.

Однако, до текущего момента не существовало какого-либо нормативного документа, специфицирующего, каким именно требованиям должен удовлетворять интерпретатор, чтобы "поддерживать" прохождение курса.

SRFI

Логотип community processЛоготип community process

Scheme Requests for Implementation -- это community process, принятый в семействе языков Scheme. В некоторых аспектах он Java Community Process или Python Enhancement Proposals. Так или иначе, это главный инструмент обсуждения развития языкового семейства, а также главный инструмент обеспечения переносимости кода.

Написание SRFI показалось автору сей заметки естественным выбором для формализации требований к программным системам.

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

Функциональная геометрия

Основой главы, посвящённой графической подсистема компьютера, в SICP послужила статься Питера Хендерсона "Функциональная Геометрия". (http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.137.1503, https://eprints.soton.ac.uk/257577/1/funcgeo2.pdf)

Образец рисунка, сделанный методом функциональной геометрииОбразец рисунка, сделанный методом функциональной геометрии

Знакомым с творчеством Морица Эшера это изображение может показаться смутно знакомым.

В основе техник функциольнальной геометрии лежат две идеи.

  • Первая идея в том, что должен существовать некоторый языковой объект painter, который при активации должен рисовать в нужном месте холста (экрана) что-то заданное программистом. (В Scheme painter -- это функция.)

  • Вторая идея в том, что нужен какой-то способ комбинировать painter'ы, получая новые painter'ы.

В КДПВ вынесена иллюстрация этого подхода.

Реализация

В предложенном SRFI не предоставленно исчерпывающей реализации метода функциональной геометрии. Однако, предложен субстрат, достаточный для того, чтобы активный студент мог сам реализовать подмножество функциональной геометрии, предложенной в SICP на любом интерпретаторе, поддерживающем SRFI-203 (результат работы автора сей заметки).

Полный текст предложения находится по ссылке:

https://srfi.schemers.org/srfi-203/srfi-203.html

Абстракт и технические детали можно найти здесь:

https://srfi.schemers.org/srfi-203/

SRFI находился на обсуждении два месяца, и за это время было предложено две реализации, для интерпретатора Chibi, и для интерпретатора Kawa.

Логотип Chibi-SchemeЛоготип Chibi-Scheme

Заключение

Автор сей заметки (он же автор SRFI) надеется, что предложенное им расширение языка будет позитивно воспринято сообществом. (Те, кто уже сейчас пользуются Scheme, могут предложить поставщикам своего интерпретатора включить это расширение в следующий выпуск.) Автор также надеется, что тем, кто начинает изучать Scheme, SICP или компьютерную графику, данное расширение также поможет сэкономить усилия, затрачиваемые на технические детали, и там самым освободить больше ресурсов для собственно обучения.

Подписка

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

  • Telegram :: http://t.me/unobvious

  • GitLab :: http://gitlab.com/lockywolf

  • Twitter :: https://twitter.com/VANikishkin

  • PayPal :: https://paypal.me/independentresearch

Подробнее..

Простой интерпретатор Lisp на Umka

26.09.2020 22:13:23 | Автор: admin

Разработка моего статически типизированного скриптового языка Umka вошла в ту стадию, когда потребовалась проверка языковых возможностей на более сложных примерах, чем скрипты в пару десятков строк. Для этого я решил реализовать на своём языке интерпретатор Lisp. На это меня вдохновил педагогический эксперимент Роба Пайка, одного из создателей языка Go. Недавно Пайк опубликовал маленький интерпретатор Lisp на Go. Особенно впечатлило замечание Пайка, что описание интерпретатора заключено на одной странице 13 древнего руководства по Lisp 1.5. Учитывая синтаксическое родство Umka и Go, было трудно не поддаться соблазну построить такой интерпретатор на Umka, но не буквальным переносом кода Пайка, а полностью заново, от основ. Надеюсь, знатоки Lisp и функциональных языков простят мне наивное изумление от соприкосновения с прекрасным.

На непосвящённых Lisp может произвести впечатление, близкое к шоку. Где граница между кодом и данными? Где циклы? Где стек? Единственной структурой данных является дерево. Оно же может представлять список. Оно же становится абстрактным синтаксическим деревом при разборе программы. Оно же заменяет собой стек при вычислении выражений. Любое дерево можно попытаться исполнить как код или использовать как данные. Вместо циклов рекурсия. В ядре языка нет даже арифметики. И тем не менее, это полный по Тьюрингу язык, который можно бесконечно расширять и посыпать синтаксическим сахаром.

Определение минимального интерпретатора Lisp действительно занимает меньше страницы. Конечно, с некоторой натяжкой: в нём используются функции, определённые на нескольких предыдущих страницах. Кажется, создатель Lisp Джон Маккарти из азарта старался превзойти сам себя в лаконизме и в итоге опубликовал микроруководство по Lisp, содержащее определение языка вместе с исходником интерпретатора в общей сложности две журнальные страницы. Правда, добавил в заголовок: "Not the whole truth".

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

Базовые конструкции языка для тех, кто с ними не знаком
  • (car x) выделение головы списка x

  • (cdr x) выделение хвоста списка x

  • (cons x y) соединение списков x и y

  • (atom x) проверка x на атомарность

  • (eq x y) проверка атомарных элементов x и y на равенство

  • (cond (a x) (b y)) выбор значения x или y по условию a или b

  • (quote x) указание использовать x как есть, без вычисления

  • ((lambda (x) a) y) вызов безымянной функции с телом a, формальным параметром x и фактическим параметром y

  • ((label ff (lambda (x) a)) y) присвоение безымянной функции имени ff

  • t истина

  • nil ложь или пустое выражение

С помощью этих конструкций можно определять и вызывать рекурсивные функции, так что в одном выражении будет заключена целая программа. Если к этому добавить ещё и арифметические функции, то можно, например, рассчитать факториал 6:

((label fac (lambda (n) (cond ((eq n 0) 1) ((quote t) (mul n (fac (sub n 1))))))) 6)

В микроруководстве Маккарти этими средствами выражен весь интерпретатор Lisp, за исключением лексического и синтаксического разбора. В руководстве Lisp 1.5 на той самой странице 13 приведён почти такой же интерпретатор, но в более человекочитаемом псевдокоде. Его я и взял за основу своего маленького проекта. Потребовалось лишь добавить разбор текста программы, некое подобие REPL и импровизированную арифметику. Роб Пайк, видимо, поступил так же, но отказался от конструкции label в пользу defn, которая позволила ему не определять функцию заново всякий раз, когда требуется её вызвать. В ядре Lisp такой возможности не предусмотрено.

Поскольку весь интерпретатор пронизан рекурсией и обработкой деревьев, он послужил отличным тестом многих возможностей языка Umka от формирования стековых кадров до сборки мусора. Думаю, Umka хорошо справился с испытанием. Исправлять пришлось лишь два-три мелких бага, связанных с экспортом имён и опережающим описанием типов. Весь код интерпретатора занял меньше 400 строк.

Желающим поиграть с моим интерпретатором и передать по эстафете вдохновение от Роба Пайка рекомендую взять папку с примерами из ветки master, а не из последнего выпуска.

Подробнее..

Перевод Почему я остаюсь с Лиспом (и вам тоже стоит)

12.02.2021 12:08:58 | Автор: admin

Зрелый язык может использоваться немногими. Но он остаётся частью моей кодовой базы.

Как давнего пользователя (и активного сторонника) Scheme/Common Lisp/Racket, меня иногда спрашивают, почему я предпочитаю их. К счастью, я всегда возглавлял собственные инженерные организации, поэтому мне никогда не приходилось оправдывать это перед руководством. Но есть еще более важная аудитория - мои собственные коллеги-инженеры, которые никогда не имели удовольствия использовать эти языки. Хотя им не требуются оправдания, они все же спрашивают из интеллектуального любопытства, а иногда и из-за удивления, почему я не схожу с ума по поводу следующей крутой функции, которая будет в этом месяце добавлена в Python или Scala, или что бы там ни было в их вкусе.

Хотя фактическая разновидность используемого мной Lisp изменялась (Scheme, Common Lisp, Racket, Lisp-for-Erlang), ядро всегда оставалось неизменным: язык программирования, базирующийся на S-выражениях, динамически типизированный, в основном функциональный, с вызовом по значению и основанный на -исчислении.

Я начал серьёзно программировать в подростковом возрасте на BASIC на ZX Spectrum+, хотя раньше я пробовал писать (вручную) программы на Fortran. Это был определяющий период для меня, поскольку он по-настоящему определил мой карьерный путь. Я очень быстро подошел к пределу языка и пытался писать программы, которые выходили далеко за ограниченные возможности языка и его реализации. Я ненадолго перешел на Паскаль (Turbo Pascal в системе DOS), что некоторое время было забавно, пока я не открыл для себя C в Unix (Santa Cruz Operation Xenix!). Благодаря этому я получил степень бакалавра компьютерных наук, но мне всегда хотелось большей выразительности в моих программах.

Это было, когда я обнаружил функциональное программирование (спасибо IISc!) В Миранде (прекрасной матери уродливого Haskell), и это открыло мне глаза на стремление к красоте в моих программах. Моё представление о выразительности языка программирования стало очень стремительно развиваться. Моя концепция того, как должны выглядеть программы, теперь заключалась в краткости, элегантности и удобочитаемости.

Миранда была не очень быстрым языком, поэтому скорость выполнения была проблемой. Миранда также была статически типизированным языком с выводом типов в стиле Standard-ML. Вначале я был очарован системой типов. Однако со временем я стал её презирать. Хотя это помогло мне уловить несколько вещей во время компиляции, в основном это мешало (подробнее об этом позже).

Примерно через год после этого я закончил изучать языки программирования в Университете Индианы у Дэна Фридмана (известного как Маленький Лиспер / Маленький Схемер). Это было мое знакомство со Scheme и миром Lisp. Я наконец понял, что нашел идеальное средство для выражения своих программ. И ничего не изменилось за последние 25 лет.

В этой статье я пытаюсь объяснить и исследовать, почему так произошло. Я просто старый динозавр, который не меняет своего образа жизни? Не слишком ли я высокомерен или может быть я пренебрежительно отношусь к новым идеям? Или я просто устал пробовать новое? Ничего из вышеперечисленного. Я нашёл совершенство, и ещё ничего лучше не появилось, чтобы повергнуть этот идеал.

Давайте разберёмся немного. Я сказал это несколькими абзацами выше:

Язык программирования, базирующийся на S-выражениях, динамически типизированный, в основном функциональный, с вызывом по значению и основнный на -исчислении.

Я собираюсь начать объяснять это - задом наперёд.

Язык, основанный на -исчислении.

Основная сущность всех программ - это функция. Функции имеют интенсиональный характер и составляют фундамент процесса проектирования программного обеспечения. Вы всегда думаете о том, как информация обрабатывается, как она трансформируется и как производится. Я ещё не нашёл фундаментальную основу, которая улавливает эту врождённую интенсиональность (как), лучше, чем -исчисление.

Возможно, слово "интенсиональность" сбивает с толку. У математики есть два способа думать о функциях. Во-первых, как набор упорядоченных пар: (вход, выход). Хотя это представление - отличный способ доказать теоремы о функциях, оно совершенно бесполезно при кодировании. Это также известно как "экстенсиональный" взгляд на функции.

Второй способ думать о функциях - это воспринимать их как правило трансформации. Например, умножить входные данные на себя, чтобы получить выходные данные (что дает нам функцию возведения в квадрат, которое на всех языках программирования удобно сокращается как sqr). Это интенсиональный взгляд на функции, который хорошо улавливается -исчислением и предоставляет простые правила, которые помогут нам доказать теоремы о наших функциях, не прибегая к экстенсиональности.

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

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

Языки программирования - это, конечно, практические инструменты, поэтому их ядро должно быть возможно более простым, чтобы соответствовать максимально широким целям. Вот почему я люблю Scheme (и мой нынешний любимый вариант, Racket - CS, как раз для тех, кто заботится о таких вещах). То, что он добавляет к основному -исчислению, - это минимум, необходимый для его использования. Даже когда эти дополнения следуют основным принципам -исчисления, есть несколько сюрпризов.

Это, конечно, означает, что рекурсия - это образ жизни. Если вы один из тех людей, для которых рекурсия никогда не имела смысла, или если вы все еще считаете, что рекурсия неэффективна, то самое время вернуться к ней. Scheme (и Racket) эффективно реализуют рекурсию в виде циклов везде, где это возможно. Более того, этого требует стандарт Scheme.

Эта фича, называемая оптимизацией хвостового вызова (или TCO - tail call optimization), существует уже несколько десятилетий. Это печальный комментарий о состоянии наших языков программирования о том, что ни один из современных языков не поддерживает. Это особенно проблема JVM, поскольку появляются новые языки, пытающиеся использовать JVM в качестве рантайм архитектуры. JVM не поддерживает TCO, и, следовательно, языки, построенные на основе JVM, должны преодолевать препятствия, чтобы обеспечить некоторое подобие иногда применимой TCO. Поэтому я всегда с большим подозрением смотрю на любой функциональный язык, основанный на JVM. По этой же причине я не стал поклонником Clojure.

Это причина номер один. Scheme/Racket - разумная реализация языка программирования, основанного на -исчислении. Как вы могли заметить, я не использую слово функциональный язык для описания схемы. Это потому, что, хотя он в первую очередь функциональный, он не полностью исключает возможность мутабельности. Несмотря на то, что Scheme не одобряет его использование, он признает, что существуют реальные контексты, в которых может быть полезна мутабельность, и разрешает её без использования вспомогательных трюков. Я не буду спорить здесь с пуристами о том, почему это так, но это связано с тем, о чем я расскажу позже в этой статье.

Вызов по значению (Call-By-Value)

Те из вас, кто знаком с деталями -исчисления, возможно, поняли, почему я решил провести это различие. Вспомните мою историю: в отношении функционального программирования мои зубы прорезалось на Miranda, который является ленивым функциональным языком (как и Haskell). Это означает, что выражения вычисляются только тогда, когда требуются их значения. Это также то, как определяется исходное -исчисление. Это означает, что аргументы функции вычисляются при их использовании, а не при вызове функции.

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

Если вы программист, один из сложнейших багов для вас - это баг, при котором отладочная печать устраняет ошибку. На ленивом функциональном языке печать чего-либо заставляет вычислять выражение, тогда как в случае с ошибками оно, возможно, не вычислялось. Таким образом, печать значений в качестве инструмента отладки становится подозрительной, поскольку она критически меняет поведение программы. Не знаю, как вы, но для меня отладочная печать - это инструмент, который кому-то придётся вырвать из моих холодных мёртвых пальцев.

Есть и другие тонкости в использовании ленивых вычислений повсюду в языке, что делает их гораздо менее привлекательным для меня. Я никогда не хочу угадывать, когда вычисляется определённое выражение. Либо вычисляйте это, либо не вычисляйте. Не заставляйте меня гадать, когда произойдёт вычисление, особенно если это произойдёт (или нет) глубоко внутри какой-нибудь библиотеки.

Вызов по значению имеет некоторые приложения в том, как доказывать формальные теоремы о программах, но, к счастью, существует чудовище, называемое "-исчислением по значению", на которое мы можем положиться в случае необходимости.

Scheme позволяет вам иметь явную ленивую оценку за счёт использования thunk-ов и мутаций, которые можно удобно абстрагировать, чтобы у вас был call-by-need, когда вам это нужно. Это подводит нас к следующему этапу.

В основном функциональный

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

Я не сторонник мутаций волей-неволей, но я сторонник их разумного использования. Как и в примере с ленивым вычислением выше, я могу полностью поддержать использование мутаций для реализации функциональных возможностей. Мутации существуют на периферии всего программного обеспечения. Для некоторых абстракций наиболее выразительным вариантом может быть преобразование мутации в небольшую красивую абстракцию. Например, шина передачи сообщений - это абстракция, заполненная мутациями, но она может иметь очень элегантные, чисто функциональные фрагменты кода, без необходимости таскать с собой ложные переменные состояния или вспомогательные устройства, такие как монады.

Как и любой другой инструмент, не-мутирующий код, доведённый до крайности, может быть вредным. Язык, который дает мне разумное использование мутаций для реализации большого объёма кода в более элегантной манере, всегда выигрывает у языка, который заставляет применять (даже хорошую) конструкцию в любой ситуации.

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

Я упомянул монады выше, так что неплохо было бы немного поговорить о них, поскольку они являются чисто функциональным способом получения эффектов. Написав о них докторскую диссертацию, я думаю, что имею некоторое представление о них. Мне нравится элегантность и чистая красота оригинальной концепции монад Eugenio Moggi. Идея отделения вычисления от значения, производимого этим вычислением, а затем преобразование этого вычисления в тип, блестящая во всех смыслах этого слова. Это отличный способ математически понять семантику языков программирования.

Но как инструмент программирования, монады вызывают у меня смешанные эмоции. Это сложный способ изолировать эффекты и затем пропустить их через всю вашу программу, когда вы можете легко создать простые абстракции, которые упростят работу с остальной частью вашей программы. Как однажды сказал выдающийся теоретик типов (который останется безымянным): Монады полезны только каждый второй вторник.

Монады - это вспомогательные устройства, которые вынуждены использовать функциональные языки, чтобы обеспечить функциональный забор от побочных эффектов. Проблема в том, что забор заразен, и все, что касается ограды, теперь тоже нужно ограждать и так далее, пока вы не дойдёте до конца детской площадки. Таким образом, вместо того, чтобы сталкиваться с побочным эффектом и элегантно обрабатывать его в абстракции, теперь вам предоставляется сложная абстракция, которую вы вынуждены таскать с собой повсюду. К тому же монады не очень композабельны.

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

Это подводит нас к следующему и, возможно, самому противоречивому мнению, которого я придерживаюсь.

Динамически типизированный

В современном мире много говорится о типизированных языках. TypeScript считается спасителем в мире JavaScript. Python и JavaScript осуждают за отсутствие статической типизации. Типы считаются важными для документации и коммуникации в крупных программных проектах. Инженерные менеджеры бросаются к ногам вывода типов, чтобы защититься от посредственных инженеров-программистов, создающих некачественный код.

Есть два типа статической типизации. Статическая типизация в старом стиле используется в C, C++, Java, Fortran, где типы используются компилятором для создания более эффективного кода. Средства проверки типов здесь очень ограничительны, но не претендуют на предоставление каких-либо гарантий помимо базовой проверки типов. Они, по крайней мере, "понимабельны".

Затем появился новый вид статической типизации, уходящий корнями в систему типов Хиндли-Милнера, который породил новое чудовище: вывод типов. Это создаёт иллюзию, что не все типы нужно объявлять. Если вы играете по правилам, вы получите не только преимущества статической типизации старого стиля, но и некоторые новые интересные вещи, такие как полиморфизм. Это взгляд тоже "понимабелен".

Но за последние пару десятилетий это приобрело новое значение: статическая типизация - это форма проверки ошибок во время компиляции, поэтому она поможет вам создавать более качественный код. Это как если бы статическая типизация - это волшебное средство доказательства теорем, которое проверит некоторые глубокие свойства вашей программы. Это то, что я называю чушью. У меня никогда не было средства проверки статического типа (независимо от того, насколько оно сложное), которое помогло бы мне предотвратить что-либо, кроме очевидной ошибки (которая в любом случае должна быть обнаружена при тестировании).

Однако то, что делают средства проверки статического типа, мешает мне. Всегда. Безошибочно. Как программист, я все время ношу в голове инварианты (причудливое название для свойств вещей в моей программе). Только один из этих инвариантов - это его тип. Иметь инструмент, который может проверить инвариант - это круто, когда вы впервые с ним сталкиваетесь (как я делал с Мирандой).

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

В старых фильмах на хинди цензура не позволяла целоваться на экране. Так романтичные сцены всегда сводились к тому, что цветы натыкались друг на друга, или пара птиц, летящих вместе, или что-то в этом роде. Вот как выглядят средства проверки статического типа. Нам преподносят красивый язык, который обещает нам право на свободу слова, но затем мы получаем пощёчину от цензуры, контролирующей речь. В конечном итоге нам приходится говорить то, что мы имеем в виду, с помощью метафор и символизма, что является лишь незначительной выгодой.

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

Все программы (статически типизированные или другие) должны иметь дело с исключениями времени выполнения. Хорошо написанные программы сталкиваются с меньшим числом таких, плохо написанные - с большим. статические тайпчекеры перемещают некоторые программы из лагеря плохо написанных в лагерь с хорошо написанными. Что улучшает (и гарантирует) качество программного обеспечения, так это тщательное тестирование. Другого решения для поставки высококачественного программного обеспечения нет. Независимо от того, используете вы статическую типизацию или нет, это лишь незначительно влияет на качество вашего программного обеспечения. Даже этот эффект исчезает, когда у вас есть хорошо разработанные программы, написанные вдумчивыми программистами.

Другими словами, статическая типизация бессмысленна. Он, возможно, имеет некоторую документальную ценность, но не заменяет документацию по другим инвариантам. Например, ваш инвариант может заключаться в том, что вы ожидаете монотонно увеличивающийся массив чисел со средним значением такого-то и такого-то и такого-то стандартного отклонения. Лучшее, что вам может сделать любая проверка статического типа, - это array[float]. Остальная часть вашего инварианта должна быть выражена словами, описывающими функцию. Так зачем подвергать себя страданиям array[float]?

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

Но, как и все остальное, иногда нужно знать типы статически. Например, я много работаю с изображениями, и мне полезно знать, что они представляют собой array[byte], и у меня есть операции, которые будут работать с ними магически быстро. Scheme/Lisp/Racket - все они предоставляют способы сделать это, когда вам это нужно. В Scheme это зависит от реализации, но Racket поставляется с вариантом Typed Racket, который можно смешивать с динамически типизированным вариантом. Common Lisp позволяет объявлять типы в определённых контекстах, в первую очередь для компилятора, чтобы реализовать оптимизацию там, где это возможно.

Итак, опять же, Scheme/Lisp/Racket дают мне преимущества типов, когда они мне нужны, но не навязывают мне ограничения повсюду. Это лучшее из обоих миров.

Базирующийся на S-выражениях

И, наконец, мы подошли к одной из наиболее важных причин, по которой я использую Lisp. Для тех из вас, кто никогда раньше не слышал термин S-выражение, он означает специфический выбор синтаксиса в Лиспе и его потомках. Все синтаксические формы представляют собой атомы или списки. Атомы - это такие вещи, как имена (символы), числа, строки и логические значения. И списки выглядят как (), где содержимое списка также является либо списками, либо атомами, и совершенно нормально иметь пустой список (). Вот и все.

Нет никаких инфиксных операций, никакого приоритета операторов, никакой ассоциативности, никаких ложных разделителей, никаких висячих else, ничего. Все функции являются префиксными, поэтому вместо того, чтобы говорить (a + b), вы должны сказать (+ a b), что дополнительно позволяет гибко сказать такие вещи, как (+ a b c). + - это просто имя функции, которую вы можете переопределить, если захотите.

Существуют keywords, которые заставляют данный список распознаваться определенным образом, но правила иерархичны и чётко определены. Другими словами, S-выражения представляют собой древовидные представления ваших программ.

Такая простота синтаксиса часто сбивает с толку новичков. Вероятно, это оттолкнуло многих программистов, которым не повезло, что они не увидели красоту этого способа написания программ.

Самым большим преимуществом этого синтаксиса является минимализм форм: вам не нужны ложные синтаксические конструкции для передачи концепций. Концепции полностью передаются с помощью имен функций или используемых синтаксических ключевых слов. Это производит странно компактный код. Не всегда компактный с точки зрения количества букв, но компактный с точки зрения количества понятий, которые необходимо учитывать при чтении кода.

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

Существует бесчисленное множество интересных синтаксических расширений, написанных поколениями лисперов, включая объектные системы, встроенные под-языки, языки предметной области и так далее. Я использовал это для разработки синтаксических функций, которые позволили мне использовать Scheme для создания вещей, которые охватывают весь диапазон от сенсорных сетей до цифровой обработки сигналов и стратегий ценообразования для электронной коммерции. В мире нет ни одного другого языка, который хотя бы приблизился к поддержке такого уровня синтаксического расширения. Это то, без чего я (и множество других лисперов) не могут жить.

Вывод

Язык программирования, базирующийся на S-выражениях, динамически типизированный, в основном функциональный, с вызовом по значению и основанный на -исчислении.

Вот почему я все еще использую Scheme/Racket/Lisp и, вероятно, буду использовать его до конца своей жизни. Использую ли я другие языки? Конечно, их много. Но никакой из них не сравнится с этим. Особенно новые. Похоже, что изобретение новых языков - это упражнение, через которое проходит каждое новое поколение плохо информированных инженеров-программистов, когда старые языки намного лучше, чем все, что они могли придумать даже во сне (я представляю вам Ruby, который, хотя номинально имеет свои корни в Лисп, напрашивается вопрос: почему вы просто не использовали сам Лисп).

Как и у всякого предубеждения, у моего тоже есть недостатки. Примерно 15 лет назад все сторонние SDK были написаны полностью на C/C ++, которые могли легко взаимодействовать с Lisp. Появление Java создало этому препятствие, поскольку JVM плохо взаимодействует со Scheme/Lisp/Racket. Это усложняло включение сторонних библиотек в мои программы без выполнения большого количества работы.

Ещё один недостаток заключается в том, что с появлением API в Интернете большинство вендоров выпускают библиотеки на распространённых в Интернете языках (Java, Ruby, Python, JavaScript, а в последнее время - Go и Rust), но никогда в Scheme/Lisp/Racket, если только это не вклад сообщества, которое также редко использует и C/C++. Это часто оставляет меня в положении, когда мне приходится самому создавать уровень API, что, конечно, не очень практично. Racket (мой нынешний фаворит) имеет довольно активное сообщество, которое вносит свой вклад в большие дела, но обычно оно немного отстает от времени, а когда дело доходит до новейших вещей, я часто остаюсь с тем что есть. Возможно, это основная причина, по которой я буду использовать Clojure в будущем, но это еще предстоит выяснить.

Меня это, конечно, еще не отпугнуло. Во всяком случае, это заставило меня лучше понять, что сообщество Lisp должно распространять своё слово все шире и шире и привлекать новое поколение Lisp, чтобы укрепить экосистему в быстро меняющейся среде.

И, наконец, проблема производительности. Во-первых, давайте развеем распространённое заблуждение: Лисп не является интерпретируемым языком. Он не медленный, и все реализации имеют множество рычагов для настройки производительности большинства программ. В некоторых случаях программам может потребоваться помощь более быстрых языков, таких как C и C++, поскольку они ближе к оборудованию, но с более быстрым оборудованием даже эта разница становится несущественной. Эти языки являются прекрасным выбором для production-quality кода и, вероятно, более стабильны, чем большинство других вариантов, благодаря десятилетиям работы над ними.

Я признаю, что изучение Scheme/Lisp/Racket немного сложнее, чем изучение Python (но намного проще, чем изучение Java/JavaScript). Однако, если вы это сделаете, вы станете гораздо лучшим программистом и научитесь ценить красоту этих языков так, что ничего другого будет недостаточно.

Anurag Mendhekar (Tech Entrepreneur and Software Artist)

Подробнее..

Перевод Пол Грэм Над чем я работал

20.02.2021 20:08:41 | Автор: admin
Февраль 2021

image

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

Первые свои программы я пытался писать на IBM 1401, его у нас в округе использовали для того, что тогда называли обработкой данных. Это было в 9 классе, так что мне было 13 или 14 лет. Этот 1401 стоял в подвале средней школы, мы с моим другом Ричем Дрейвсом получили разрешение использовать его. Тот подвал был похож на логово бондовского злодея, в котором хранится куча инопланетных устройств процессоры, жесткие диски, принтер, устройство для чтения карт, и все это под яркими флуоресцентными лампами.

Мы писали на одной из первых версий Фортрана. Программы нужно было набирать на перфокартах, затем складывать их в устройство для чтения карт и нажимать на кнопку, чтобы программа загружалась в память и запускалась. Обычно в результате ее работы что-то печаталось на невероятном громком принтере.


image

IBM 1401

Тот 1401 был для меня загадкой. Я не понимал что с ним можно делать, Оглядываясь назад, ясно, что я особо ничего и не мог. Единственной формой передачи входных данных были перфокарты, а я на них ничего не хранил. В качестве альтернативы можно было писать программы, не полагающиеся на входные данные (вроде приближенных вычислений числа пи), но я не очень хорошо знал математику для этого. Именно поэтому я не удивлен, что не могу вспомнить ни одной своей программы из того времени потому что они мало чего умели. Лучше всего мне запомнился тот момент, когда я узнал, что программы могут и не завершаться (когда одна из моих не завершилась). Учитывая, что у того компьютера не было ограничений по времени использования, это была не только техническая, но и социальная ошибка об этом мне сообщил менеджер центра обработки данных.

Все изменилось с появлением микрокомпьютеров. У нас появились компьютеры, стоящие на столе прямо перед нами, они реагировали на нажатия кнопок прямо во время работы, а не перебирали стопку перфокарт и отключались. [1]

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

image


Heathkit H8 Digital Computer Kits

Компьютеры тогда стоили дорого, мне пришлось годами уламывать отца, прежде чем он купил TRS-80 примерно в 1980 году. Золотым стандартом тогда был Apple II, но TRS-80 тоже был довольно хорош.

image

TRS-80

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

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

Я не мог выразить это словами, когда мне было 18 лет. Я продолжал ходить на курсы по философии, и они были скучны. Именно поэтому я начал заниматься ИИ.

Об ИИ много говорили в 1980-ых, но мне особую мотивацию придали две вещи: роман Хайнлайна под названием Луна суровая хозяйка, в котором использовался умный компьютер по имени Майк, и документальный фильм от PBS, в котором Терри Виноград использовал SHRDLU.

image

SHRDLU

Я не пытался перечитывать роман Хайнлайна, потому что понимаю, что он устарел, но в те годы я погрузился в мир этой книги. Казалось, что появление Майка лишь вопрос времени, и когда я увидел как Виноград использует SHRDLU, мне показалось, что на его создание уйдет несколько лет. Казалось, что нужно лишь обучить SHRDLU большему количеству слов.

Тогда в Корнелле не было курсов по ИИ, так что мне пришлось учиться самому. Это значило, что мне нужно было выучить Lisp, потому что тогда он был языком ИИ. В то время большинство языков программирования были примитивными, а значит идеи программистов были такими же. По умолчанию в Корнелле все писали на паскалеподобном языке PL/I, он использовался почти повсеместно. Изучение Lisp настолько расширило мое понимание концепции программ, что ограничения я начал понимать лишь спустя годы. Именно этого я и ожидал от колледжа. Этого эффекта не было от занятий в классах, но это нормально. Следующие пару лет я был в ударе. Я понимал что собираюсь делать.

Для своей бакалаврской выпускной работы я занимался реверс-инжинирингом SHRDLU. Боже, как мне нравилось заниматься этой программой. Было приятно писать тот код, но еще более захватывающе было думать о том (сейчас в это трудно поверить, но в 1985 так думали многие), что те программы были действительно умными и покоряли вершины ИИ.

Я учился в Корнелле на программе, в рамках которой не подразумевался выбор специальности. Для получения степени было посещать любые занятия, которые нравились. Я, конечно, выбрал Искусственный интеллект. Когда я получил на руки диплом, я встревожился наличию этих кавычек. Тогда меня это беспокоило, но теперь мне это кажется до забавного точным (по причинам, которые мне только предстояло узнать).

Я подал документы в 3 аспирантуры: Массачусетского Технологического, Йеля, который тогда славился в области ИИ, и Гарварда его я посетил поскольку туда пошел Рич Дрейвз, а также там жил Билл Вудс, разработавший парсер для моего клона SHRDLU. Меня приняли только в Гарвард, так что туда я и пошел.

Не помню когда это произошло и было ли это в какой-то конкретный момент, но в первый год обучения я понял, что концепция ИИ это ложь. Я говорю об ИИ того типа, в котором программе сообщают, что собака сидит на стуле, а та переводит эти сведения в некое формальное представление и добавляет их в свою базу знаний.

Все эти программы показывали, что существуют подмножества натурального языка языки формальные. Очень полезные подмножества. Было ясно, что существует огромный разрыв между их возможностями и реальным пониманием естественного языка. В целом, просто обучить SHRDLU большему количеству слов было недостаточно. Методы создания ИИ на основе структур данных, представляющих концепции, не сработал. Его крах, как это часто случается, породил возможности для написания статей о всевозможных заплатках для него, но все это не позволило бы нам создать Майка.

Я стал думать, что из обломков моих планов можно спасти, и вспомнил про Lisp. По своему опыту работы с ним я знал, что этот язык интересен сам по себе, даже в отрыве от ИИ (хотя в то время люди занимались им только в этом контексте). Именно поэтому я решил сосредоточиться на Lisp. Я решил написать книгу о хакерстве на Lisp. Страшно подумать насколько мало я об этом знал, когда начинал писать книгу. Впрочем, нет ничего лучше написания книги, чтобы разобраться в какой-либо теме. Книга о Lisp была опубликована в 1993, но большую ее часть я написал в аспирантуре.

Computer Science это непростой союз теории и систем. Теории позволяют строить доказательства, а с помощью систем люди строили и создавали. Я хотел создавать. Я с большим уважением относился к теории (на самом деле, подозреваю, что эта половина более прекрасна), но казалось, что создавать что-то будет интереснее.

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

image


Xerox Star 8010 Dandelion

В какой-то момент в лаборатории появились несколько лишних компьютеров Xerox Dandelion. Любой желающий поиграться с ним мог его взять. Я сам ненадолго соблазнился, но по нынешним стандартам они были очень медленными, так что какой смысл? Никому они были не нужны, а потому и исчезли. Именно так все и происходило с системами.

Я хотел не просто что-то создавать, а создавать что-то, что будет служить долго.

Будучи неудовлетворенным, я поехал к Ричу Дрейвзу в Институт Карнеги-Меллона, он там учился в аспирантуре. Однажды я заходил в Институт Карнеги, в детстве я там проводил много времени. Я рассматривал картину и до меня дошла мысль, которая кажется очевидной, хотя тогда она меня удивила. Прямо там на стенах висели вещи, которые делались надолго. Картины не устаревали. Возраст некоторых из лучших составлял сотни лет.

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

Мне всегда нравилось смотреть на картины. Мог ли я сам их писать? Тогда я понятия не имел. Я даже представить себе не мог, что это возможно. Умом я понимал, что искусство творят люди что оно не возникало само по себе, но эти творцы будто принадлежали к другому виду. Они либо жили давно, либо это загадочные гении, о чудачествах которых пишут в Life. Мысль о том, чтобы заняться искусством, казалась невероятной.

Той осенью я начал посещать уроки творчества в Гарварде. Аспиранты могли посещать занятия всех факультетов, а мой научный руководитель Том Читэм был очень спокойным и простым человеком. Даже если он и знал о странных курсах, которые я посещал, они никогда и ничего не говорил.

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

Я не видел выхода из этой ситуации. Я не хотел бросать аспирантуру, но что мне оставалось? Я помню как моего друга Роберта Морриса выгнали из Корнелла за то, что он написал интернет-червя в 1988 году я завидовал, что он нашел столь захватывающий способ бросить аспирантуру.

Однажды в апреле 1990 года все сдвинулось с места. Я столкнулся с профессором Читэмом он спросил смогу ли я выпуститься в июне. К тому моменту я не написал ни слова, но в тот момент я принял самое быстрое решение в жизни я решил написать диссертацию примерно за 5 недель до крайнего срока, по возможности переиспользуя фрагменты своей книги On Lisp. Именно поэтому я без промедления ответил Думаю, да. Я дам вам материалы для прочтения через несколько дней.

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

Попутно я пытался поступить в художественную школу. Я подавал документы Род-Айлендскую школу дизайна и Венецианскую академию изящных искусств (поскольку я полагал, что это старейшая из хороших школ). Меня приняли в Род-Айлендскую, а ответа из Флоренции я так и не дождался, так что я отправился с Провиденс. Я пошел на программу для бакалавров изящных искусств (BFA), а это означало, что по сути я опять пошел в колледж. Это было не так странно, как кажется, поскольку мне было 25, а в художественных школах полно людей разного возраста. В Школе меня посчитали второкурсником и сказали, что мне нужно подготовить фундамент. Фундаментом называли базовые курсы по рисованию, цвету и дизайну.

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

Только страньери (иностранцы) должны были сдавать вступительные экзамены. Оглядываясь назад, я понимаю, что видимо это был способ отсеивать иностранцев, потому что в противном случае итальянцы были бы в меньшинстве. В то лето я был в хорошей форме в плане рисования и живописи, но не понимал как сдавать письменный экзамен, Я помню, что ответил на вопрос в эссе, написав о Сезанне я вытянул интеллектуальный уровень на максимум, который позволял мой ограниченный словарный запас. [2]

Мне было всего 25, и в моей жизни уже проявились интересные закономерности. Я снова стремился поступить в престижное учебное заведение с целью изучить какой-нибудь престижный придет, и я снова был разочарован. Студенты и преподаватели в академии были замечательными, но у них было негласное соглашение студенты не требовали, чтобы их учили, а академия не требовала, чтобы студенты что-либо изучали. При этом все происходило с условностями ателье из XIX века. У нас действительно стояла печка, которая топилась дровами, и обнаженная модель, которая сидела к ней максимально близко, чтобы не обжечься. Кроме меня почти никто ее не рисовал. Остальные студенты болтали или пытались подражать тому, что видели в американских журналах об искусстве.

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

Во время учебы в академии, по ночам в своей комнате я рисовал натюрморты. Эти картины были маленькими: во-первых, сама комната была маленькой, а во-вторых, я рисовал их на обрывках холста большего я себе не мог позволить. Рисование натюрмортов отличается от рисования людей (потому что как следует из названия, объекты двигаться не могут). Люди не могут сидеть неподвижно больше 15 минут, и даже в это время они не замирают полностью. Стандартный метод рисования людей знать как рисовать типичного человека, а затем подстраивать эти знания под того человека, которого вы рисуете. Натюрморт же можно пиксель за пикселем копировать с того, что вы видите. Конечно, не хочется останавливаться на достигнутом, иначе вы получите фотографическую точность натюрморты интересны именно тем, что они проходят через голову художника. Вам захочется подчеркивать визуальные особенности, которые, например, сообщают о том, что резкая смена цвета в точке описывает край объекта. Тонко подчеркивая такие моменты, вы можете создавать картины, которые будут более реалистичными, чем фотографии не только в метафорическом, но и в строгом теоретико-информационном смысле. [5]

Мне нравилось рисовать натюрморты, потому что мне было любопытно то, что я вижу. В повседневной жизни мы не задумываемся о том, что мы видим. Большая часть визуального восприятия связана с низкоуровневыми процессами именно они сообщают вашему мозгу, что это капля воды, не сообщая подробностей о ее самых светлых и темных областях, или позволяют опознать куст, не сообщая его форму и положение всех листьев. Это особенность мозга, а не ошибка в его работе. В повседневной жизни было бы неудобно отвлекаться на каждый отдельный листик. Но когда вы хотите что-то нарисовать, вам нужно приглядеться, а когда вы это делаете, вам есть на что посмотреть. Вы можете замечать новые и новые детали после попыток нарисовать что-то, что остальные принимают как должное так же вы можете подмечать новые мысли после нескольких дней попыток написать эссе о том, что все считают очевидным.

Это не единственный способ рисования. Я не уверен на 100%, что он вообще хорош. Впрочем, мне он казался стоящим, а значит нужно было попробовать.

Наш учитель, профессор Уливи, был хорошим человеком. Он видел, что я много работал, и ставил мне хорошие оценки в дневник, который был у каждого студента. Впрочем, академия не учила меня ничему кроме итальянского, а также у меня стали заканчиваться деньги, так что в конце первого года я вернулся в США.

Я хотел вернуться в Род-Айлендскую школу дизайна, но я был разорен, а учиться там было дорого. Из-за этого я решил устроиться на работу на год, а затем продолжить обучение следующей осенью. Я устроился в Interleaf, эта компания занималась разработкой ПО для создания документов. Вроде Microsoft Word? Да, именно. Именно тогда я понял, что дешевое ПО может поглощать ПО высокого уровня. Впрочем, Interleaf оставалось жить еще несколько лет. [5]

Порой в Interleaf делали смелые вещи. Компания была вдохновлена Emacs и создала свой язык для написания сценариев это был диалект Lisp. Компании нужен был хакер на Lisp, который писал бы на этом языке. То, чем я там занимался, наиболее похоже на нормальную работу из всего, чем я занимался (прошу прощения у своего начальника и коллег я был плохим сотрудником). Их Lisp представлял собой тонкий слой глазури на огромном торте из Си, а поскольку я его не знал и учить не хотел, большую часть ПО компании я не понимал. К тому же я был ужасно безответственным. Тогда работа программистом подразумевала приход на рабочее место в определенное время. Мне это казалось противоестественным, и сейчас весь мир сходится к моему образу мышления, но тогда из-за этого возникало немало конфликтов. Ближе к концу года большую часть времени я тайком писал On Lisp книга получила контракт на публикацию.

К счастью, мне платили огромные деньги, особенно по меркам студентов-художников. Во Флоренции, после оплаты аренды, мой бюджет составлял 7 долларов на день. Теперь же мне платили в 4 раза больше, даже если я просто сидел на собрании. Живя экономно, мне удалось не только накопить на возвращение в Род-Айлендскую школу дизайна, но и рассчитаться по ссудам на учебу.

В Interleaf я многому научился (хотя в основном понял чего делать не надо). Я узнал, что технологическими компаниями лучше руководить людям, специализирующимся на продуктах, а не продажах (хотя понимание продаж важный навык, и люди, которые им обладают действительно круты), что если над кодом работает слишком много человек, то в нем накапливаются баги, что дешевый офис будет нерентабелен, если он всех удручает, что запланированные встречи уступают разговорам в коридоре, что большие клиенты-бюрократы могут быть опасным источником денег, и что рабочие время и место для написания кода не обязательно пересекаются с оптимальными.

Но самый важный, урок который я усвоил (он пригодился мне как в Viaweb, так и в Y Combinator) заключается в том, что нет ничего плохого в том, чтобы работать на начальном уровне, даже если это не так престижно. В противном случае кто-то может просто вдавить вас в потолок. Все это значит, что престиж может быть опасен.

Следующей осенью я возвращался в Род-Айлендскую школу дизайна, и я договорился о внештатной работе в конторе, занимавшейся разработкой различных проектов для клиентов именно на этом я и выживал следующие несколько лет. Когда я вернулся к одному из проектов, кто-то рассказал мне о новом языке, HTML вроде как он был производной от SGML. Энтузиазм к языкам разметки был издержками профессии в Interleaf, и я их игнорировал, хотя позже этот самый HTML стал важной частью моей жизни.

Осенью 1992 года я вернулся в Провиденс, чтобы продолжить учебу в Школе дизайна. Я только начал вникать в основы, а учеба в академии была просто смешной. Теперь я собирался увидеть на что похожа настоящая художественная школа. Увы, она была скорее похожа на Венецианскую Академию. Конечно, все было куда более организованно (и куда дороже), но стало ясно, что художественная школе не имеет того же отношения к искусству, как медицинская к медицине. По крайней мере, на факультете художников. У модельеров (на него учился мой сосед), кажется, все было куда строже. То же самое касалось иллюстраторов и архитекторов. Но в живописи все было не очень строго. Студенты-художники должны были самовыражаться, что для простых людей означало поиски собственного стиля.

Фирменный стиль это визуальный эквивалент того, что в бизнесе называют фишкой: именно благодаря нему люди могут понять, что эта работа принадлежит вам, а не кому-то другому. Например, когда вы видите картину в мультяшном стиле, вы понимаете, что ее написал Рой Лихтенштейн. Если вы увидите такую картину в квартире менеджера хедж-фонда, то будет ясно, что он заплатил за нее миллионы долларов. Не у всех художников есть свой фирменный стиль, хотя обычно клиенты платят именно за него. [6]

Серьезных студентов тоже было немало: ребята, которые умели рисовать в старшей школе, а теперь пришли в лучшую художественную школу в стране, чтобы научиться рисовать еще лучше. Они были сбиты с толку и деморализованы тем, что видели в Род-Айлендской школе дизайна, но они продолжали идти туда, потому что рисовали, Я не был из тех, кто умел рисовать в старшей школе, но я был ближе к этим людям, чем к искателям авторского стиля.

Я многому научился на уроках колористики, но в остальном я самостоятельно учился рисовать, и я мог делать это бесплатно. В 1993 я бросил учебу. Я немного погулял по Провиденсу, а потом моя подруга по колледжу Нэнси Пармет оказала мне большую услугу. Квартира с умеренной арендной платой в доме, которым владела ее мать в Нью-Йорке, пустовала. Хотел ли я туда заехать? Она была ненамного больше моей собственной квартиры, а в Нью-Йорке было много художников. Так что да, я хотел! [7]

Комиксы об Астериксе начинаются в крошечном уголке Галлии, который, как оказывается, не контролируется римлянами. Что-то похожее есть и в Нью-Йорке: если вы приблизите карту Верхнего Ист-Сайда, то увидите крошечный небогатый район (по крайней мере, он был таким в 1993). Он называется Йорквилл, это был мой новый дом. Я стал Нью-Йоркским художником (чисто технически я рисовал и жил в Нью-Йорке).

Я нервничал из-за денег потому что чувствовал, что Interleaf идет ко дну. Фриланс на Lisp попадался редко, и я не хотел писать на другом языке в те дни это был бы С++, если бы мне повезло. У меня был безошибочный нюх на финансовые возможности, так что я решил написать еще одну книгу о Lisp. Это была более простая и популярная книга, которую можно использовать как учебник. Я представлял себе как экономно живу на гонорары и провожу все свое время за рисованием (рисунок для обложки этой книги, ANSI Common Lisp, я нарисовал примерно в то время).

image


Больше всего мне в Нью-Йорке нравилось, что там жили Идель и Джулианна Вебер. Идель Вебер была художницей, одной из первых начала работать в стиле фотореализма, я посещал ее занятия в Гарварде. Я никогда не видел, чтобы учителя так любили ученики. С ней поддерживали связь большинство бывших студентов, в том числе и я. После переезда в Нью-Йорк я стал де-факто ее студийным ассистентом.

Ей нравилось писать на больших квадратных холстах, шириной от 4 до 5 футов. Однажды в конце 1994 года, когда я растягивал одного из этих монстров, по радио рассказывали что-то об одном известном фондовом менеджере. Он был ненамного старше меня и был очень богат. Мне вдруг пришла в голову мысль: почему бы мне не стать богатым? Тогда я смогу работать над чем захочу.

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

Если я хотел разбогатеть, то это был поезд, подходящий к станции. Я был прав в сути, но ошибся с идеей. Я решил, что нужно создать компанию для размещения художественных галерей в интернете. Прочитав множество заявок в Y Combinator, я могу сказать, что это худшая идея для стартапа. Художественные галереи не хотели выходить в интернет и до сих пор не хотят, даже самые модные. Их продажи работают иначе. Я написал ПО для создания сайтов для галерей, а Роберт написал несколько программ для изменения размеров изображения и настройки HTTP-сервера, отдававшего страницы. Потом мы пытались заключить договоры с галереями. Сказать, что это было сложно ничего не сказать. Даже раздавать наш продукт было сложно. Несколько галерей разрешили нам сделать для них сайты бесплатно, но никто нам не платил.

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

Итак, летом 1995 года, после того как я передал издателям готовую рукопись ANSI Common Lisp, мы начали пытаться писать ПО для создания интернет-магазинов. Сначала это должно быть ПО для настольных компьютеров, а значит для Windows. Это была тревожная перспектива мы не умели писать программы для Windows и не хотели учиться. Мы жили в мире Unix. Но мы все же решили написать прототип конструктора магазина под Unix. Роберт написал корзину, а я написал генератор сайтов конечно, на Lisp.

Мы работали в квартире Роберта в Кембридже. Его соседа там подолгу не было, я в это время спал на его месте. Почему-то не было ни корпуса кровати, ни простыней, только матрас на полу. Однажды утром, когда я лежал на этом матрасе, меня посетила идея, из-за которой я свернулся буквой Г. Что если мы будем запускать ПО на сервере и позволим пользователям управлять им, нажимая на ссылки? Тогда нам не нужно было бы ничего писать для клиентских компьютеров. Мы могли бы создавать сайты на том же сервере, с которого они отдавались. Пользователям не понадобится ничего, кроме браузера.

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

Мы почувствовали, что у нас что-то получается. У нас было видение ПО нового поколения, которое должно было работать таким образом. Больше не были нужны версии, порты и все такое. В Interleaf была целая команда релиз-инженеров, и они работали не меньше разработчиков. Теперь же ПО можно было обновлять прямо на сервере.

Когда нам удалось развернуть свое ПО в сети, мы основали компанию. Она называлась Viaweb и мы получили свое первое официальное финансирование 10 000 долларов от Джулианна, мужа Идель. В обмен на деньги, помощь с юридическими вопросами и советы по ведению бизнеса, мы передали ему 10% компании. Десять лет спустя эта сделка стала образцом для Y Combinator. Мы знали, что основателям нужно нечто подобное, потому что сами нуждались в этом.

В то время мой баланс был отрицательным, поскольку имевшаяся у меня тысяча (или около того) долларов уравновешивалась моими долгами по налогам (откладывал ли я деньги, которые зарабатывал за консультации Interleaf? Нет, не откладывал). Итак, несмотря на то, что Роберт получал стипендию для аспирантов, мне нужно было начальное финансирование на жизнь.

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

Изучение искусств помогло, поскольку главная задача разработчика интернет-магазина сделать так, чтобы все солидно выглядело для пользователя, а ключом к этому являются высокие стандарты. Если правильно сверстать страницы и подобрать цвета и шрифты, то можно сделать так, что парень, управляющий магазином из своей спальни, будет солиднее большой компании.

(Если вам любопытно почему мой сайт выглядит столь старомодно он сделан с помощью этого самого ПО. Сегодня он может казаться неуклюжим, но в 1996 он был передовым.)

В сентябре Роберт восстал. Мы работаем над этим проектом уже месяц, но он все еще не завершен, сказал он. В ретроспективе это особенно забавно, потому что он работал над ним и три года спустя. Но я решил, что стоит нанять еще программистов и спросил Роберта о крутых ребятах в его аспирантуре. Он порекомендовал Тревора Блэквелла, что сначала удивило меня, поскольку он стремился все сводить в стопку записок, которую всюду носил с собой. Но Роберт, как всегда, был прав. Тревор невероятно эффективно писал код.

Работать с Робертом и Тревором было очень весело. Это два человека с самыми независимыми умами, которых я знаю, причем они совершенно разные. Если заглянуть в голову к Роберту, то у него там все выглядит как в церкви в Новой Англии, а у Тревора там излишества австрийского рококо.

Мы открылись с 6 магазинами в январе 1996. Хорошо, что мы выждали несколько месяцев, потому что хоть тогда мы и боялись, что опаздываем, на самом деле было слишком рано. Тогда в прессе много писали об электронной коммерции, но не многие хотели заводить свои интернет-магазины. [8]

Наше ПО состояло из трех основных частей: редактора для создания сайтов, который писал я, корзины для покупок, которую писал Роберт и менеджера для отслеживания заказов и статистики, который писал Тревор. В свое время наш продукт был одним из лучших универсальных конструкторов сайтов. Я писал код лаконично и мне не приходилось подключать свои программы к чему-либо, кроме проектов Роберта и Тревора, так что работать над всем этим было довольно весело. Если бы следующие 3 года мне нужно было только работать над этим ПО, это было бы самое легкое время в моей жизни. К сожалению, нужно было делать и много другого, что получалось у меня хуже написания кода, а потому следующие три года были самыми напряженными.

Во второй половине 90-ых было много стартапов, занимавшихся разработкой ПО для электронной коммерции. Мы были полны решимости создать Microsoft Word, а не Interleaf. Для этого наш продукт должен был быть простым в использовании и недорогим. Нам повезло, что мы сами были бедными, это заставило нас удешевить Viaweb еще сильнее. Мы брали 100 долларов в месяц за небольшой магазин и 300 за большой. Эта низкая цены была одновременно соблазном и бременем для конкурентов, но мы установили ее не из-за разумных соображений. Мы понятия не имели какие бизнесы нам платят и как они это делают. 300 долларов в месяц казались нам большими деньгами.

Много правильных решений мы приняли случайно. Например, мы делали то, что сейчас называют немасштабируемыми решениями, хотя тогда мы это описали бы как нечто настолько неубедительное, что мы идем на отчаянные меры для привлечения пользователей. Самым распространенным таким проявлением было создание магазинов для клиентов. Это казалось нам особенно унизительным, ведь вся суть существования нашего ПО заключалась в предоставлении людям возможности создавать свои магазины. Но мы были готовы на все, чтобы получить пользователей.

Мы узнали о розничной торговле больше, чем хотели бы, Например, если у нас была небольшая фотография рубашки (а по нынешним меркам все картинки тогда были маленькими), то лучше было иметь крупный план воротника, чем кадр со всей рубашкой. Помню как узнал об этом, потому что это означало, что мне придется переделать 30 картинок с рубашками. Впрочем, их первые версии тоже были красивыми.

Хоть это и казалось неправильным, это было правильное решение. Создание магазинов для клиентов позволило нам многое узнать о розничной торговле и об использовании нашего ПО. Сначала меня оттолкнул сам бизнес я думал, что нам понадобится человек из бизнеса, который бы всем руководил, но как только мы начали привлекать пользователей я изменился так же, как после рождения детей. Чего бы ни хотели пользователи, я был в их власти. Может быть однажды к нам пришло бы настолько много пользователей, что я больше не мог бы делать для них картинки с рубашками, но в тоже время не было ничего более важного.

Была и другая вещь, которую я тогда не понял. Я не осознавал, что темп роста главное испытание для стартапа. У нас было около 70 магазинов в конце 1996 года и около 500 в конце 1997. Я ошибочно думал, что решает абсолютное количество пользователей. Это важно с точки зрения ваших доходов если их не будет хватать, вы можете выйти из бизнеса. Но в долгосрочной перспективе темп роста выправляет абсолютное число пользователей. Если бы мы были стартапом, который я консультировал в YCombinator, я бы сказал так: хватит нервничать, у вас все хорошо. У вас семикратный прирост каждый год, Просто не нанимайте слишком много людей, тогда ваш бизнес станет прибыльным, а вы сможете контролировать свою судьбу.

Увы, я нанял много людей. Отчасти из-за того, что таким было желание наших инвесторов, а отчасти из-за того, что во времена интернет-пузыря многие так делали. Таким образом, мы не достигли безубыточности вплоть до сделки с Yahoo в 1998 году. Это, в свою очередь, означало, что мы были во власти инвесторов на протяжении всего срока жизни компании. А поскольку и мы, и наши инвесторы, были новичками в стартапах, в результате творился беспорядок даже по меркам стартапов.

Когда мы ушли под Yahoo, пришло большое облегчение. В целом, акции Viaweb были ценными. Они представляли собой долю в быстрорастущем бизнесе. Но для меня все это было не слишком ценно. Я понятия не имел как оценивать бизнес, но я слишком хорошо чувствовал околосмертные переживания, которые, кажется, наступали каждые несколько месяцев. С тех пор, как мы начали, я не изменил существенно свой аспирантский стиль жизни. Поэтому когда нас купила Yahoo, это был переход из грязи в князи. Поскольку мы переезжали в Калифорнию, я купил желтый VW GTI 1998 года выпуска. Думаю, кожаные сидения этой машины были моим наиболее роскошным имущуством.

В следующем году, с лета 1998 по лето 1999, наверное выдался наименее продуктивный отрезок моей жизни. Тогда я этого не осознавал, но я очень устал от усилий и стрессов, связанных с запуском Viaweb. Какое-то время после переезда в Калифорнию я пытался действовать по-прежнему. Я программировал до трех часов ночи, но усталость вместе с преждевременно состарившейся корпоративной культурой Yahoo и мрачным офисом в Санта-Кларе постепенно меня добили. Через несколько месяцев мне стало очень неприятно, как во времена работы в Interleaf.

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

Когда я сказал, что ухожу, мой босс в Yahoo долго беседовал со мной о моих планах. Я рассказал ему о том, какие картины хочу нарисовать. Тогда я был тронут его интересом. Теперь я понимаю, что ему просто казалось, что я лгу. Тогда мои опционы стоили примерно 2 миллиона долларов. Если бы я просто оставил эти деньги, их хватило бы для основания нового стартапа, а для этого мог бы взять с собой других людей. В те годы интернет-пузырь был на пике, и Yahoo была эпицентром той эпохи. Мой босс на тот момент был миллиардером. Уход из Yahoo с целью основания нового стартапа казался ему безумным, но при этом амбициозным планом.

Но я действительно уходил, чтобы рисовать, и я сразу взялся за это. Терять время было нельзя. Я и так прожег 4 года, чтобы разбогатеть. Теперь, когда я разговариваю с основателями, которые уходят после продажи своей компании, я всегда даю один совет: возьмите отпуск. Вот что я должен был сделать, просто уйти куда-нибудь и месяц или два и ничего не делать, но эта идея мне никогда не приходила в голову.

Я пытался рисовать, но похоже, что у меня не было ни энергии, ни амбиций. Отчасти проблема заключалась в том, что я почти никого не знал в Калифорнии. Я усугубил ее, купив прекрасный дом в Калифорнии с замечательным видом, который находился за много миль от моих любимых мест. Я продержался несколько месяцев, а затем в отчаянии вернулся в Нью-Йорк. Вы будете удивлены, если не знаете о том, как организован контроль за арендой жилья в Нью-Йорке, потому что квартира была запечатана и похожа на гробницу моей старой жизни. По крайней мере, Идель все еще была в Нью-Йорке, и там были и другие люди, которые пытались рисовать, хотя я никого из них не знал.

Когда я вернулся в Нью-Йорк, я начал жить по-прежнему, только теперь я был богат. Это было именно настолько странно, как и звучит. Я делал все как раньше, хотя появились и новые возможности. Если я уставал от пеших прогулок, мне нужно было лишь поднять руку (если не шел дождь), чтобы меня подобрало такси. Теперь, когда я проходил мимо очаровательных ресторанов, я мог зайти и заказать обед. Какое-то время это было захватывающе. Рисование стало получаться лучше. Я экспериментировал с новым методом рисования натюрмортов: сначала я рисовал картину как обычно, затем фотографировал ее, распечатывал, размещал ее на холсте, а затем использовал как подмалевок для второй картины, написанной с этих же объектов (которые, как я надеялся, не сгнивали за это время).

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

Примерно в это же время, весной 2000 года, у меня появилась идея. Из нашего опыта с Viaweb стало ясно, что будущее за веб-приложениями. Почему бы не создать веб-приложение для создания веб-приложений? Почему бы не дать людям возможность редактировать код на нашем сервере через браузер, а затем размещать в сети получившиеся приложения? [9] Пользователи могли бы запускать на серверах всевозможные сервисы, которые эти приложения могли бы использовать просто с помощью запросов к API: совершение и прием звонков, обработка изображений, прием платежей с кредитных карт и т.д.

Я был так взволнован этой идеей, что не мог думать ни о чем другом. Факт, что за этим будущее, казался очевидным. Я не очень хотел создавать новую компанию, но было ясно, что эту идею нужно будет воплотить как единое целое, так что я решил переехать в Кембридж и взяться за нее. Я надеялся заманить Роберта поработать со мной над этим проектом, но он теперь был постдоком в MIT. Несмотря на то, что когда я приглашал его в прошлый раз, он заработал много денег, также он потерял немало времени. Хоть он и соглашался с тем, что идея может сработать, он категорически отказался работать над ней.

Хм. Что ж, значит мне предстояло все сделать самому. Я нанял Дэна Гиффина, который работал в Viaweb, и двух студентов, которые искали работу на лето, и мы взялись за дело. Теперь ясно, что наш проект впору разбить на 20 компаний и несколько проектов с открытым исходным кодом. Язык для разработки приложений, конечно, был диалектом Лиспа. Впрочем, я не был настолько наивен, чтобы полагать, что смогу продвинуть Лисп среди широких масс. Мы скрывали скобки, как это делал Дилан.

К тому времени Viaweb можно было назвать провайдером прикладных услуг (ASP). Это название прожило недолго, его заменили на Software as a service (ПО как услуга), но новую компанию я все равно назвал Aspra.

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

К моему удивлению, время на этот проект не было потрачено зря. После запуска YCombinator я часто видел стартапы, работающие с частями этой новой архитектуры, было полезно потратить время на размышления и даже попробовать что-то написать на эту тему.

В итоге проект с открытым исходным кодом, которым я занимался, стал новой версией Лиспа, скобки которой и скрывать не хотелось. Многие люди, пишущие код на Лиспе, мечтают создать новый Лисп. Отчасти дело в том, что одна из отличительных черт этого языка заключается в множестве его диалектов, а отчасти в том, что где-то в нашем сознании существует платоническая форма Лиспа, от которой идут все диалекты. К концу лета мы с Дэном взялись за работу над новым диалектом Лиспа, который мы назвали Arc, в новом доме, который я купил в Кембридже.

Следующей весной прогремел гром. Меня пригласили выступить на конференции по Лиспу, я рассказывал как мы писали на нем в Viaweb. Я разместил постскрипт этого выступления на paulgraham.com, который создал задолго до Viaweb, но совсем не использовал. Однажды страница с выступлением набрала 30 000 просмотров. Что, черт возьми, произошло? По URL-ссылкам стало ясно, что кто-то разместил мое выступление на Slashdot [10]

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

Все это было возможно с 1993, но никто об этом не задумывался. Я был тесно связан с развитием инфраструктуры интернета, писал тексты, но даже мне понадобилось 8 лет, чтобы прийти к этой мысли. Затем мне потребовалось еще несколько лет, чтобы осознать последствия. Это значило, что грядет новое поколение эссе [11]

В эпоху печати каналов для публикации эссе было очень мало. За исключением нескольких общепризнанных мыслителей, ходивших на правильные вечеринки в Нью-Йорке, публиковать эссе разрешалось только специалистам, пишущим о своей деятельности. Многие эссе так и не были написаны из-за отсутствия каналов для их публикации. Канал появился, и я собирался писать. [12]

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

Я знал, что поначалу сфера онлайн-эссе будет маргинальной. В социальном плане эти тексты больше походили на тирады психов с GeoCities, чем на благородные и красиво набранные тексты из The New Yorker. Но к этому моменту я знал достаточно, чтобы это обнадеживало, а не пугало.

Одна из самых заметных закономерностей, которые я замечал в своей жизни это то, насколько хорошо (по крайней мере для меня) работать над тем, что не считается престижным. Натюрморт всегда был наименее престижным видом живописи. Когда мы начинали, всем казалось, что Viaweb и YCombinator никому не нужны. Незнакомцы до сих пор удивляются, когда я говорю, что пишу эссе и собираюсь опубликовать его на своем сайте. Даже Лисп, который считается интеллектуально престижным (примерно как латынь) кажется просто модным.

Дело не в том, что непрестижные работы хороши сами по себе. Но если вы понимаете, что вас тянет к какой-то работе, несмотря на ее проблемы с престижем, это говорит о том, что в ней есть что-то правильное, и что у вас правильные мотивы. Неправильные мотивы большая проблема для амбициозных людей. Если что-то и может сбить вас с верного пути, то это желание произвести впечатление на людей. Таким образом, хоть работа над непрестижными вещами и не гарантирует, что вы на правильном пути, по крайней мере он гарантирует, что вы не на популярном неправильном пути.

В течение нескольких следующих лет я написал множество эссе на самые разные темы. O'Reilly издали их сборник под названием Хакеры и художники, после одного эссе о них. Также я работал над фильтрами спама и продолжал рисовать. Я приглашал друзей на ужин по вечерам в четверг, что научило меня готовить для группы людей. Позже я купил в Кембридже еще одно здание, бывшую леденцовую фабрику (и как позже оказалось, бывшую порностудию) для использования в качестве офиса.

Однажды в октябре 2003 года у меня дома проходила большая вечеринка. Это была отличная идея моей подруги Марии Дэниэлс, она однажды приходила на ужин в четверг. Три разных хозяина приглашали гостей на вечеринки. Таким образом, на каждого гостя две трети других гостей будут незнакомцами, которых те хотели бы узнать. Одним из гостей была незнакомая мне девушка, которая мне очень понравилась: Джессика Ливингстон. Пару дней спустя я пригласил ее на свидание.

Джессика отвечала за маркетинг в Бостонском инвестиционном банке. Руководство этого банка было уверено в том, что разбирается в стартапах, но в следующем году, когда Джессика встретилась с моими друзьями из мира стартапов, она была удивлена, насколько все расходилось с реальностью. Также ее удивили их яркие и красочные рассказы. Поэтому она решила написать книгу-сборник интервью с основателями стартапов.

Когда у банка начались финансовые трудности и им пришлось сократить половину штата, Джессика начала искать новую работу. В начале 2005 года она прошла собеседование на маркетинговую должность в Бостонской венчурной фирме. Им потребовалось несколько недель на принятие решения, и за это время я начал рассказывать ей обо всем, что нужно знать о венчурном капитале. Что компании нужно делать много небольших инвестиций вместо нескольких гигантских, что им следует финансировать более молодых и близких к технологиям основателей, а не MBA, что нужно оставлять основателей на позиции генерального директора и так далее.

Один из моих приемов для написания эссе выступление с докладом. Перспектива встать перед группой людей и рассказать им о чем-то, что не потратит их время зря, была большим стимулом для воображения. Когда Гарвардское компьютерное сообщество (компьютерный клуб бакалавров) попросил меня выступить с докладом, я решил, что расскажу им о создании стартапов. Может быть, им удастся избежать худшей из ошибок, что мы сделали.

Итак, я выступил с этим докладом. Я сказал, что лучшими источниками финансирования для стартапов могут быть основатели успешных стартапов, поскольку они также могут помочь советом. Тогда казалось, что все слушатели выжидающе смотрят на меня. В ужасе от перспективы, что мой почтовый ящик будет завален бизнес-планами (если бы я только знал), я выпалил: Но только не я! и продолжил доклад. Но потом мне пришло в голову, что стоит перестать откладывать это дело и стать бизнес-ангелом. Я хотел заняться этим еще во времена нашей сделки с Yahoo, с тех пор прошло 7 лет, а я не сделал ни одной инвестиции.

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

Когда мы с Джессикой шли домой после ужина 11 марта на углу улиц Гарден и Уокер, эти три нити сошлись. К черту венчурных инвесторов, которые так долго принимали решение. Мы решили открыть собственную инвестиционную фирму и воплотить в жизнь идеи, о которых говорили. Я профинансировал бы эту компанию, а Джессика могла бы уйти со своей работы и начать работать с нами, а Роберт и Тревор стали бы нашими партнерами. [13]

Незнание снова сработало в нашу пользу. Мы понятия не имели как быть бизнес-ангелами, а в 2005 еще не было Рона Конвея, у которого можно было бы учиться. Мы просто сделали очевидный выбор, а некоторые из наших решений оказались новыми.

YCombinator состоит из нескольких компонентов, и мы не сразу сформулировали их все. В первую очередь мы стали фирмой-ангелом. Тогда эти два слова не стыковались. Тогда были венчурные фирмы, чья работа заключалась исключительно в инвестировании, но они делали только крупные инвестиции в миллионы долларов. И были ангелы, которые делали небольшие инвестиции, но это были люди, которые обычно были сосредоточены на других вещах и инвестировали на стороне. Никто из них не мог достаточно помогать основателям в начале пути. Мы знали, насколько беспомощными могут быть основатели, потому что помнили как сами были беспомощны. Например, Джулиан в свое время сделал то, что казалось нам волшебством основал компанию. Мы прекрасно писали ПО, а законное оформление, акции и прочее что это вообще такое? Мы собирались заниматься не просто посевными инвестициями, мы хотели делать все то, что Джулиан сделал для нас.

YC изначально не был фондом. Компания была не слишком затратной, так что мы финансировали ее собственными средствами. У 99% читателей это вопросов не вызовет, а профессиональные инвесторы подумали Вау, значит они забрали себе всю прибыль. Опять же, это произошло не из-за проницательности с нашей стороны. Мы не знали как устроены венчурные фирмы. Нам никогда и в голову не приходило собрать фонд, а если бы пришло, то мы бы не знали с чего начать. [14]

Главная отличительная черта YC это пакетная модель, Мы финансировали сразу несколько стартапов два раза в год, а затем три месяца пытались интенсивно им помогать. Это получилось не только неявно, но и явно из-за того, что мы мало знали об инвестировании. Нам нужно было получить опыт. Мы подумали что может быть лучше, чем финансировать сразу несколько стартапов? Мы знали, что летом студенты получают временную работу в технологических компаниях. Почему бы не организовать летнюю программу, где вместо этого запускали бы стартапы? Мы не чувствовали себя виноватыми в том, что в некотором смысле являемся фальшивыми инвесторами, поскольку они в том же смысле являлись фальшивыми основателями. Вероятно, нам не предстояло заработать на этом много денег, но мы могли попрактиковаться в инвестициях, а ребята, с которыми мы будем работать, проведут лето интереснее, чем работая в Microsoft.

В качестве штаб-квартиры мы использовали принадлежавшее мне здание в Кембридже. Мы все ужинали там раз в неделю (по вторникам, потому что в четверг я готовил ужины), а после ужина приглашали экспертов по стартапам для выступления.

Мы знали, что студенты решают вопрос о летней работе за считанные дни, так что мы придумали летнюю программу для основателей. Я разместил объявление о ней на своем сайте и приглашал студентов подавать заявки. Я никогда не думал, что написание эссе позволит создать поток сделок, как это делают инвесторы, но все сработало. [15] В итоге мы получили 225 заявок на участие в Летней программе для основателей и обнаружили, что многие из подавших заявки либо закончили учебу, либо вот-вот заканчивали. Вся эта история с летней программой стала казаться более серьезной, чем мы предполагали.

Мы пригласили 20 из 225 групп на очные собеседования, и в 8 из них мы решили инвестировать. Это была впечатляющая группа. В первый поток вошли Reddit, Джастин Кан и Эммет Шир, которые впоследствии основали Twitch, Аарон Шварц, который уже помог написать спецификацию RSS и через несколько лет станет мучеником за открытый доступ, и Сэм Альтман, который позже стал вторым президентом YC. Не думаю, что первый поток был хорош только благодаря удаче. Нужно было проявить смелость, чтобы записаться на такую программу вместо работы в солидном месте вроде Microsoft или Goldman Sachs.

Сделка для стартапов была основана на сочетании сделки, которую мы заключили с Джулианом (10 тысяч долларов за 10%), и того, что, по словам Роберта, получили аспиранты Массачусетского технологического института на лето (6 тысяч долларов). Мы инвестировали 6 тысяч долларов на основателя, что в среднем означало 12 тысяч в обмен на 6%. Это должно было быть справедливо, потому что это вдвое лучше сделки, которую мы заключили в свое время. Плюс то лето действительно жарким, и Джессика организовала основателям бесплатные кондиционеры. [16]

Вскоре я понял, что мы наткнулись на способ увеличения финансирования стартапов. Пакетное финансирование для нас было удобнее, посколька оно позволяло что-то делать для большого количества стартапов одновременно, а также им самим было полезнее работать в группах. Это также решало одну из самых больших проблем, с которой сталкиваются основатели: изоляция. Теперь у основателей были не только обычные коллеги, но и коллеги, которые понимали их проблемы и делились методами их решения.

С ростом YC мы начали замечать и другие преимущества роста. Выпускники стали сплоченным сообществом, они стремились помогать друг другу и стартапам в нынешних группах, потому что помнили каково было им самим. Мы также заметили, что стартапы становились клиентами друг друга. Раньше мы в шутку говорили о ВВП YCombinator, но теперь в этом все меньше и меньше шутки. Теперь многие стартапы получают первых клиентов среди своих товарищей по группе.

Изначально я не планировал делать YC своей основной и полноценной работой. Я собирался заниматься тремя вещами: писать код, писать эссе и работать в YC. По мере роста YC, я все больше вовлекался в его дела, и в итоге он стал отнимать больше трети моего внимания. Но первые несколько лет я мог спокойно заниматься другими делами.

Летом 2006 года мы с Робертом начали работу над новой версией ARC. Она была довольно быстрой, поскольку компилировалась в Scheme. Чтобы проверить работоспособность этого языка, я написал на нем Hacker News. Изначально это должен был быть агрегатор новостей для основателей стартапов, он назывался Startup News, но уже через несколько месяцев я устал читать исключительно о стартапах. К тому же, мы не хотели обращаться к основателям стартапов. Мы хотели достучаться до будущих основателей. Так что я изменил название на Hacker News, а темой могло стать все, что интересовало интеллектуальное любопытство.

NH, безусловно, был полезен для YC, но он стал большим источником стресса для меня. Если бы мне нужно было только выбирать основателей и помогать им, жизнь была бы очень легкой, Но это значило бы, что HN был ошибкой. В то время я был похож на человека, испытывающего боль во время марафона не из-за усталости и напряжения, а из-за волдыря от неподходящей обуви. Когда я сталкивался с неотложными проблемами во времена работы с YC, они с вероятностью 60% относились к HN и 40%, что ко всему остальному вместе взятому. [17]

Помимо HN, я написал все внутренне ПО для YC на Arc. Но пока я продолжал писать на Arc, я постепенно перестал работать над самим языком. Отчасти из-за нехватки времени, а отчасти из-за того, что от него зависела инфраструктура. Так что теперь у меня было два проекта: эссе и YC.

YC не был похож на работу, которой я занимался раньше. Я больше не мог выбирать над чем работать, проблемы сами приходили ко мне. Каждые 6 месяцев появлялась новая партия стартапов, и их проблемы (какими бы они ни были) становились нашими. Это было увлекательно, поскольку их задачи были разнообразны, а хорошие основатели были очень продуктивны. Если бы вы хотели узнать о стартапах как можно больше в сжатые сроки, то способа лучше просто нет.

Были и части работы, которые мне не нравились. Споры между соучредителями, попытки выявить ложь, борьба с людьми, грубо обращающихся со стартапами и так далее. Но я много работал и над тем, что мне не нравилось. Мне преследовала мысль Кевина Хейла: Никто не работает больше, чем начальник. Это была и описательная мысль, и предписание, и меня пугала вторая ее сущность. Я хотел, чтобы YC был успешен, а если то, как я работаю, описывает верхнюю планку работы всех остальных, то мне лучше работать очень усердно.

Однажды в 2010 году в Калифорнию приезжал Роберт Моррис, и он сделал нечто удивительное дал мне непрошеный совет. Я такое от него помню лишь однажды. Однажды в Viaweb я согнулся пополам из-за камня в почке, и Роберт решил, что ему стоит отвезти меня в больницу. Именно такие поводы нужны были Роберту для того, чтобы дать непрошеный совет. Так что я очень хорошо запомнил его слова: Знаешь, ты должен убедиться, что YCombinator не последнее твое крутое дело.

Тогда я не понимал что он имел в виду, но скоро до меня дошло, что он советует мне уйти. Этот совет казался странным, поскольку у YC все шло отлично. Если что-то и случалось реже, чем непрошенные советы от Роберта, то это его ошибки. Это заставило меня задуматься. Действительно, на той траектории YC стал бы последним моим делом, потому что он сам отнимал очень много моего внимания. Он уже поглотил Arc и начал поглощать эссе. Либо YC должен был стать делом моей жизни, либо мне нужно было уйти. И я решился.

Летом 2012 года у моей мамы случился инсульт, причиной которого стал тромб, вызванныф раком прямой кишки. Инсульт уничтожил ее равновесие и мы поместили ее в дом престарелых, но она хотела выбраться из него и вернуться домой. Мы с сестрой были полны решимости помочь ей в этом. Я часто летал в Орегон, чтобы навестить маму, и на этих рейсах у меня было много времени для размышлений. На одном из них я понял, что готов передать YC кому-то другому.

Я спросил Джессику не хочет ли она стать президентом, но она отказалась, так что мы решили нанять Сэма Альтмана. Мы поговорили с Робертом и Тревором и договорились о полной смене караула. До этого момента YC контролировался LLC, основанным нами вчетвером. Мы хотели, чтобы YC жил долго, а значит нельзя было отдать управление основателям. Так что если Сэм согласится, то мы дали бы ему возможность реорганизовать YC. Мы с Робертом ушли бы на пенсию, А Джессика и Тревор стали обычными партнерами.

Когда мы спросили Сэма хочет ли он стать президентом YC, он сперва ответил отрицательно. Ох хотел запустить стартап по производству ядерных реакторов. Я продолжал настаивать, и в октябре 2013 он наконец согласился. Мы решили, что он возьмет на себя управление, начиная с потока зимы 2014 года. До конца 2013 года я передавал Сэму все больше полномочий отчасти, чтобы он мог освоить эту работу, а отчасти, потому что я был сосредоточен на своей матери, у которой вернулся рак.

Мама умерла 15 января 2014 года. Мы знали, что этот момент был близок, но когда это случилось, было тяжело.

Я продолжал работать в YC до марта, чтобы помочь стартапам добраться до демо-дня, а затем проверял результаты (я все еще общаюсь с выпускниками и новичками, работающими над тем, что меня интересует, но на это уходит всего несколько часов в неделю).

Что мне делать дальше? В совете Роберта ничего об этом не говорилось. Я хотел заняться чем-то другим, так что вернулся к рисованию. Я хотел увидеть чего смогу добиться, если сосредоточусь на этом. Итак, на следующий день, после ухода из YC, я начал рисовать. Я был не в форме и мне потребовалось время, чтобы ее вернуть, но это было увлекательно. [18]

Большую часть 2014 года я провел за рисованием. Мне никогда не удавалось работать так непрерывно, и я должен был стать лучше, чем раньше. Я был не слишком крут, но все же лучше. Затем в ноябре, прямо посреди работы над картиной, я выдохся. До этого момента мне всегда было интересно увидеть какой получится картина, над которой я работал, но внезапно завершение этой показалось мне рутинной работой. Я перестал работать над этой картиной, почистил кисти, и больше этим не занимался по крайней мере, пока.

Я понимаю, что звучит слабо. Но напоминаю это игра с нулевой суммой. Если вы можете выбрать над чем работать и выбрали не лучший (или просто не очень хороший) проект для себя, то он будет мешать другому проекту. А в 50 появилась неплохая упущенная ранее возможность бездельничать.

Я снова начал писать эссе и написал кучу новых текстов в течение следующих нескольких месяцев. Я даже написал пару статей, не касавшихся стартапов. Затем в марте 2015 года я снова начал работать над Лиспом.

Отличительная черта Лиспа заключается в том, что его ядро это интерпретатор языка, написанный на нем самом. Изначально он не задумывался как язык программирования в привычном понимании. Он должен был быть формальной моделью вычислений, альтернативой машине Тьюринга. Если вы хотите написать интерпретатор для языка, какой минимальный набор предопределенных операторов вам нужен? Лисп, который изобрел (или, вернее, открыл) Джон Маккарти, является ответом на этот вопрос. [19]

Маккарти не понимал, что этот Лисп можно было использовать для программирования на компьютерах, пока это не предложил его студент Стив Рассел. Рассел перевел интерпретатор Маккарти на машинный язык IBM 1704, и с этого момента Лисп стал языком программирования в привычном понимании этого слова. Но его происхождение как модели вычислений придало ему силу и элегантность, с которыми другие языки не могли сравниться. Именно это привлекало меня в колледже, хотя я не понимал почему.

Лисп Маккарти 1960 года не умел ничего кроме интерпретации выражений. Ему не хватало многих вещей, которые хочется иметь в языке программирования. Их пришлось добавить, а когда они появились, то они не были определены с помощью аксиоматического подхода Маккарти. Тогда это было невозможно. Маккарти тестировал свой интерпретатор вручную, моделируя выполнение программ. Он приближался к пределу интерпретаторов, которые можно было протестировать таким образом там была ошибка, которую Маккарти не заметил. Чтобы протестировать более сложный интерпретатор, его нужно было запустить, а тогдашние компьютеры были недостаточно мощными.

Теперь же они достаточно мощны. Вы можете использовать аксиоматический подход Маккарти, пока не определите полноценный язык программирования. И покуда ваши изменения, вносимые в Лисп Маккарти, сохраняют принцип того, что он был открыт, а не изобретен, вы можете создать полноценный язык с этим качеством. Сделать это конечно сложнее, чем говорить, но если это возможно почему не попробовать? Я решил попробовать. На это ушло 4 года, с 26 марта 2015 года по 12 октября 2019. К счастью, у меня была четко определенная цель, иначе трудно было бы этим так долго заниматься.

Я написал новый Лисп, названный Bel, на Arc. Может показаться, что тут есть противоречие, но это показатель того, что мне пришлось прибегнуть к хитрости, чтобы заставить все работать. С помощью ряда уловок, мне удалось написать нечто максимально близкое к работоспособному интерпретатору языка, написанному на этом же языке. Он не слишком быстр, но достаточно быстр для тестов.

Большую часть того времени я запрещал себе писать эссе, иначе я никогда бы не закончил, В конце 2015 года я выделил 3 месяца на написание эссе, и когда я вернулся к работе над Bel, я едва мог понимать код. Не потому, что он был плохо написан, просто программа была запутанной. Когда вы работаете над интерпретатором для языка, написанным на этом же языке, сложно отслеживать что и на каком уровне происходит, ошибки могут быть зашифрованы до момента их получения.

Так что я больше не писал эссе, пока не закончил работу над Bel. В эти годы могло казаться, что я ничего не делаю, хотя я работал больше, чем когда-либо. Иногда после нескольких часов борьбы с жуткими багами я заходил на HN или в Твиттер и видел посты вроде А пол Грэм еще пишет код?

Работа над Bel была сложной, но она приносила удовлетворение. Я работал над ним так интенсивно, что у меня в голове постоянно были куски кода, и я мог писать больше и больше. Я помню как в солнечный день в 2015 году ходил со своими мальчиками на пляж и думал как решить проблему с продолжениями, наблюдая как ребята играют в волнах прибоя. Я помню этот момент, потому что был встревожен его новизной. Хорошо, что в следующие несколько лет у меня было больше таких моментов.

Летом 2016 года мы переехали в Англию. Мы хотели, чтобы наши дети получили опыт проживания в другой стране, а поскольку по рождению я был гражданином Великобритании, этот выбор был очевидным. Мы хотели побыть там всего год, но нам так понравилось, что мы решили остаться. Большая часть Bel была написана в Англии.

Осенью 2019 я закончил работу над Bel. Как и оригинальный Лисп Маккарти, это скорее спецификация, чем реализация, и как и Лисп Маккарти это спецификация, выраженная в коде.

Теперь я снова мог вернуться к написанию эссе. Я охватил кучу интересных мне тем. Я продолжил писать эссе до 2020 года, а потом снова стал думать над чем я мог бы работать. Как выбрать чем заниматься? А как я раньше делал этот выбор? Я написал для себя эссе, чтобы ответить на эти вопросы и был удивлен насколько длинным и запутанным получился ответ. Я подумал, что если он удивил меня, человека, который все это прожил, то насколько интересно это будет другим людям? Может этот текст вдохновит и других людей, чья жизнь столь беспорядочна? Я написал для них более развернутую версию, чтобы другие люди могли ее прочитать и это ее последнее предложение.

Примечания


[1] В моем опыте пользования ПК пропущена одна эпоха: машины с разделением времени и интерактивными ОС. Я перешел от перфокарт сразу к микрокомпьютерам, что сделало последние менее захватывающими.

[2] Значение итальянских слов, обозначающих общие понятия, можно предсказать по их английским аналогам (за исключением ловушек вроде Polluzione). Различаются только повседневные слова. Если вы свяжете какое-то количество общих понятий и простых глаголов, вы сможете немного продвинуться в изучении итальянского.

[3] Я жил на Пьяцце Сан-Феличе 4, так что мои прогулки до Академии проходили по всей старой Флоренции: мимо Питти, через Мост, мимо Орсанмикеле, между Дуомо и Баптистерием, затем по улице Виа Риказоли до площади Сан Марко. Я видел улицы Флоренции в самых разных состояниях: от темных зимних вечеров, когда они были пусты, до жарких летних дней, когда улицы заполнены туристами.

[4] Конечно, вы можете рисовать людей как натюрморты, если хотите (и если они готовы). Такой портрет, вероятно, является вершиной натюрморта, хотя долгая неподвижность вызывает у натурщиков болезненные выражения.

[5] Interleaf была одной из многих компаний, у которой были умные люди, которые создавали крутые технологии, но все это было раздавлено законом Мура. В 1990-ые экспоненциальный рост мощности процессоров (например, от Intel) сковал компании, выпускающие специализированное программное и аппаратное обеспечение.

[6] Искатели фирменного стиля из Род-Айлендской школы дизайна не обязательно наемники. Все дорогое становится крутым, а все, что кажется крутым, вскоре станет дорогим.

[7] Технически, аренда у квартиры не контролировалась, а была стабилизирована, но все эти вещи понятны только жителям Нью-Йорка. Суть в том, что она была очень дешевой, ниже половины от рыночной стоимости.

[8] Большую часть ПО можно выпускать после завершения разработки, но если вы работаете над конструктором интернет-магазинов и у вас нет пользователей, то все не так просто. Перед публичным запуском нам пришлось провести частный запуск, то есть набрать ограниченную группу пользователей и убедиться, что они получают приличные магазины.

[9] У нас был редактор кода в Viaweb, который позволял создавать свои собственные стили страниц. Пользовали этого не знали, но под капотом они редактировали выражения на Лиспе. Но это не был редактор приложений, поскольку код запускался при создании сайтов продавцами, а не при их посещении покупателями.

[10] Это был первый пример такого опыта, который позже стал привычным. То же самое произошло, когда я прочитал комментарии и обнаружил там множество разгневанных людей. Как я только мог утверждать, что Лисп лучше других языков? Разве они не были Тьюринг-полны? Люди, которые видят реакции на мои эссе, порой говорят, что им меня жаль. Я не преувеличиваю, когда говорю, что так было с самого начала. Все это приходит с распространением. Эссе рассказывают людям о том, чего они еще не знают, а людям это не нравится.

[11] Конечно, в 90-е люди много чего выкладывали в интернет, но выложить в интернет и опубликовать это разные вещи. Публикация подразумевает, что вы рассматриваете интернет-версию как основную.

[12] Есть один общий урок, который мы извлекли из опыта работы с YCombinator: обычаи будут ограничивать вас долгое время после того, как исчезнут вызвавшие их условия. Когда-то обычные практики венчурных инвестиций, как и приемы написания эссе, были основаны на реальных ограничениях. Запускать стартапы стоило дороже, а потому это происходило редко. Теперь они могли быть дешевыми и распространенными, но обычаи венчурных капиталистов отражали порядки старого мира, так же как обычаи написания эссе по-прежнему отражали обычаи старой эпохи печати.

Все это значит, что люди с независимым мышлением (то есть менее подверженные влиянию обычаев) будут иметь преимущество в быстро меняющихся областях (где обычаи будут с большей вероятностью устаревать);

Интересные момент: не всегда можно предсказать какие поля будут затронуты быстрыми переменами. Очевидно, что это справедливо для ПО и венчурных инвестиций, но кто мог подумать про написание эссе?

[13] Название YCombinator не было изначальным. Сначала мы назвали компанию Cambridge Seed. Мы хотели избавиться от названия с региональной привязкой на случай, если кто-то из Кремниевой Долины нас скопирует, так что мы переименовали компанию в честь одного из самых классных приемов в лямбда-исчислении: Y-комбинатора.

Я выбрал оранжевый как наш основной цвет, потому что он теплый, и потому что его не использовали другие венчурные фонды. В 2005 все венчурные фонды использовали строгие цвета: темно-бордовый, темно-синий и зеленый, потому что они пытались привлечь внимание ограниченных партнеров, а не основателей. Логотип YC это внутренняя шутка. Логотип Viaweb представлял собой белую букву V в красном круге, так что я логотип YC это белая буква Y в оранжевом квадрате.

[14] Начиная с 2009 года, YC пару лет был фондом, но потом он настолько разросся, что я больше не мог финансировать его самостоятельно. Впрочем, после покупки Heroku, у нас было достаточно денег, чтобы вернуться к самофинансированию.

[15] Мне никогда не нравился термин поток сделок, потому что он подразумевает, что количество новых стартапов в любой момент времени фиксировано. Это ложь, и цель YC опровергнуть это утверждение, помогая основывать стартапы, которых в противном случае не существовало бы.

[16] Джессика рассказывала, что все они были разных форм и размеров, потому что был огромный спрос на кондиционеры, а ей нужно было найти все, что можно было. Все они были тяжелее, чем она могла бы нести на себе.

[17] Еще одна проблема HN странный краевой случай, который возникает, когда вы пишете эссе и ведете форум. Когда вы ведете форум, предполагается, что вы видите если не все беседы вообще, то все беседы с вашим участием. Когда вы пишете эссе, люди постят на форумах весьма вольные и неверные их интерпретации. По отдельности эти явления утомительны, но терпимы, а вместе губительны. На неверные интерпретации нужно реагировать, потому что предположение о том, что вы присутствуете в разговоре, подразумевает отказ от ответа на неверное толкование, ставшее популярным, и означает признание его правильности. С другой стороны, это ободряет: любой, кто захочет сразиться с вами, будет чувствовать, что у него есть шанс.

[18] Самое печальное в уходе из YC было то, что больше мы не работали с Джессикой. Мы работали над YC почти все время, что были знакомы, и мы не пытались и не хотели отделять эту работу от нашей личной жизни. Этот уход был похож на вырывание глубоко укоренившегося дерева.

[19] Один из способов разделить концепции изобретения и открытия поговорить о пришельцах. Любая достаточно развитая инопланетная цивилизация наверняка знает о теореме Пифагора. Верю (хоть и с меньшей уверенностью), что они слышали о Лиспе из статьи Маккарти 1960 года.

Но если это и так, то нет оснований предполагать, что это предел известного им языка. Вероятно, пришельцам будут нужны числа, ошибки и ввод/вывод. Так что существует по меньшей мере один вариант того, что Лисп Маккарти был открытием.

Спасибо Тревору Блэквеллу, Джону Коллисону, Патрику Коллисону, Дэниелу Гаклу, Ральфу Хазеллу, Джессике Ливингстон, Роберту Моррису и Харджу Таггару за чтение черновиков этого текста.



Следите за новостями YC Startup Library на русском в телеграм-канале или в фейсбуке.

Полезные материалы


Подробнее..

Перевод Что не так с Лиспом?

23.02.2021 16:14:33 | Автор: admin

Во-первых, позвольте мне сказать, что лично я не думаю, что с Лиспом что-то особенно не так. Таким образом, в этом эссе я не буду пытаться отвечать на риторический вопрос в заголовке. Тем не менее, я попытаюсь проанализировать некоторые часто повторяющиеся критические замечания в адрес Lisp, чтобы пролить свет на этот вопрос и на то, почему его так часто задают.

Позвольте мне начать с пары слов для тех кто не в курсе. Lisp - это семейство языков, включая Common Lisp, Emacs Lisp и несколько диалектов, которые сегодня используются лишь изредка. Иногда даже язык Scheme считается членом этого семейства. Считать ли это верным, зависит от того, каково ваше точное определение Lisp, но это является слишком сложным (и неинтересным) вопросом для этого эссе.

В основном я буду использовать Lisp для обозначения Common Lisp, а иногда, когда это удобно, также буду включать Emacs Lisp. Lisp существует уже давно, хотя он был значительно преобразован с момента своего изобретения (некоторые говорят, что он был открыт). Сегодня это современный, мультипарадигменный язык, который обладает, пожалуй, самыми сложными фичами из всех используемых языков общего назначения (объектная система CLOS, языковые макросы, специальные макросы чтения, система условий и рестартов и т. д.).

Первый вопрос, который часто задают: Если Lisp настолько хорош, почему он не популярен?. Люди, которые задают такой вопрос, обычно предполагают, что хороший подразумевает популярный, и поэтому ищут какую-то часть Lisp, которая НЕ является хорошей, что могло бы объяснить, почему он не популярен. Однако нет абсолютно никаких оснований предполагать, что хороший подразумевает популярный, поэтому вопрос действительно довольно наивный. Но вместо того, чтобы просто игнорировать этот вопрос в некоторых частях этого эссе, я на мгновение приму его за чистую монету и попытаюсь объяснить, почему Lisp не так популярен, как хотели бы некоторые его последователи.

Однако позвольте мне сделать небольшое замечание. Lisp не настолько непопулярный, как можно думать (и теперь для удобства я добавлю Emacs Lisp). В недавнем подсчете количества строк Lisp занял 4-е место по количеству строк исходного кода (SLOC) в дистрибутиве Debian GNU/Linux (Woody) после C, C++ и bash с примерно 4 миллионами SLOC (около 4%), опередив Perl, Python, ML, Fortran и т. д. Это довольно популярный язык, лишь несколько менее популярный, чем C и C++. Конечно, количество SLOC в Debian GNU/Linux - не единственный возможный показатель популярности, но это показатель, как и любой другой.

Недавно я увидел статью в comp.lang.lisp, в которой автор серьезно знал, что с Lisp должно быть что-то не так, потому что, если все будет хорошо, рынок обнаружит это, и Lisp начнет использоваться в программных проектах повсюду. Тот факт, что этого не произошло, доказал автору, что с Лиспом ДОЛЖНО быть что-то не так, даже если он не знал, что именно.

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

Возможно, в Lisp действительно что-то не так, потому что он, кажется, привлекает всевозможных психов, хотя, возможно, я просто не знаю, что это так и для других языков, или для любого другого человеческого артефакта. Обычно это проявляется в случае с Лиспом так: кто-то, плохо знакомый с Лиспом, впервые появляется в группе новостей comp.lang.lisp, дает очень умным и очень знающим людям урок о том, что они не поняли, почему Lisp непопулярен, и продолжает рассказывать им, как им следует изменить язык, чтобы исправить проблему (обычно, изменить синтаксис, чтобы избавиться от множества скобок), или просто сообщить им, что они сделали ошибку, и вместо этого следует использовать другой язык.

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

Подводя итог этому эссе, они просто жертвы невероятно сильного психологического стремления (в некоторой степени, существующего во всех нас), которое заставляет человека пытаться обозначить что-то новое как плохое или бесполезное, просто чтобы избежать тяжелой работы, необходимости учиться этому. Чем страннее новая вещь (например, Lisp), тем сложнее человек оценивает работу по ее изучению и тем важнее становится объявить ее плохой или бесполезной.

Итак, как нам исправить Lisp, чтобы сделать его более привлекательным для таких людей? Лично я не думаю, что мы должны пытаться изменить что-то в Лиспе, чтобы привлечь этих людей. Почему быть популярным - это все, что имеет значение в языке программирования?!

Я часто вижу очень показательную параллель, проводимую между Лиспом и хорошей скрипкой. Должны ли мы изменять скрипки, чтобы привлечь людей, которые привыкли играть на аккордеоне и не хотят учиться игре на скрипке, потому что это слишком сложно и слишком отличается от аккордеона? Конечно, нет! У скрипки есть свое место, и она становится прекрасным инструментом, когда играет тот, кто действительно владеет ею.

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

Некоторые люди думают, что с Лиспом что-то не так, потому что практически невозможно заставить программное обеспечение работать без изменений на всех платформах (комбинациях Лисп-систем и операционных систем), тогда как с чем-то вроде Python или Ruby это легко. Ясно же, что здесь с Лиспом что-то не так, верно?

Нет, на самом деле нет! Lisp - это не отдельная реализация, а ANSI-стандарт (теперь уже Common Lisp). Как и многие другие стандарты (например, ANSI-стандарт для языка программирования Си), он не содержит всего, что вам может понадобиться при написании приложений, например сокетов, синтаксических анализаторов XML, библиотек SQL и т. д. Вместо этого предоставляются отдельные библиотеки, которые в случае Lisp либо поставляются поставщиком коммерческой системы Lisp, либо бесплатно авторами свободных библиотек для других разработчиков. Таким образом, предполагаемая трудность состоит в том, чтобы написать приложение, которое могло бы работать со всеми этими, возможно, взаимно несовместимыми библиотеками. Разработчик, столкнувшийся с этой проблемой, обычно очень расстраивается, жалуется в comp.lang.lisp, что мы должны исправить стандарт ANSI Common Lisp как можно скорее, чтобы включить эти библиотеки.

Подождите секунду! Почему это не проблема для таких языков, как Python и Ruby, которые даже НЕ ИМЕЮТ стандарта ANSI? Почему люди не жалуются громко, что они даже не могут написать кросс-платформенный цикл или оператор присваивания на Python, потому что способ сделать это не стандартизирован? Ответ: потому что эти люди сравнивают яблоки и апельсины или, в данном случае, язык, определяемый (в основном) одной реализацией, и стандарт с несколькими реализациями. Вот как увидеть, насколько это сравнение абсурдно: если бы я написал новую реализацию Python, в которой не было бы сокетов, разве это внезапно ухудшило бы положение языка Python, в сравнении с тем, что было раньше? Конечно, нет! Точно так же люди, которые хотят использовать язык с единственной реализацией и тем самым рискуют, что язык может измениться в одночасье, что, возможно, сделает большую часть некоторых крупных инвестиций устаревшими, должны принять то же самое с Lisp и выбрать единственную реализацию. который работает во всех операционных системах. Это будет не хуже, чем у любого языка с одной реализацией.

Некоторые ВНУТРИ Lisp-сообщества думают, что Lisp не так популярен, как он того заслуживает, потому что в языке есть недостатки. Таким образом, предполагаемое решение проблемы состоит в создании лучшего диалекта Lisp. Откровенно говоря, если бы это было правдой, то ни у одного другого языка не было бы ни единого последователя, учитывая количество недостатков в других языках по сравнению с недостатками Common Lisp. Одной из типичных попыток создать лучший Lisp был Dylan (больше похожий на Scheme, чем на Lisp, на самом деле), который определяет синтаксис без скобок для Lisp-подобного языка, тем самым по существу лишая Lisp одного из его, пожалуй, величайших преимуществ, а именно почти однозначного соответствия между внешним синтаксисом и внутренним представлением кода, что является важной фичей для создания макросов. А Dylan не более популярен, чем Common Lisp.

В последнее время мы регулярно видим людей (обычно также в сообществе Lisp), у которых есть идеальное объяснение того, почему Lisp не так популярен, как он того заслуживает, а именно, что нет ни одной бесплатной реализации, которая работала бы во всех операционных системах и в которой были бы ВСЕ необходимые библиотеки, как в Python и Ruby для веб-программирования и т. д. (мы уже видели, что в стандарте ANSI Common Lisp их нет). Типичная статья одного из этих людей очень снисходительна. Недавно я видел фразы, похожие на Простите, ребята, но интерфейсы командной строки больше не подходят, в наши дни все основано на графическом интерфейсе, а у вас даже нет стандартной библиотеки графического интерфейса.

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

Большинство авторов этих статей, кажется, серьезно думают, что каким-то образом они будут серьезно восприняты участниками Lisp-сообщества, и что эти участники осознают свои ошибки и начнут предоставлять высококачественные библиотеки для веб-программирования и синтаксического анализа XML бесплатно и сразу. Я не думаю, что это случится. Чтобы понять, почему, мы можем (для этой цели) разделить членов "сообщества Lisp" на три типа людей:
- тех, кто уже тратит значительную энергию и время на написание таких библиотек,
- тех, кто не имеет возможности писать такие библиотеки. (из-за недостатка знаний, энергии или времени), и
- тех, у кого есть возможность сделать это, но они не делают этого.

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

Люди из второй категории не собираются вдруг начать писать нужные библиотеки.

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

Меня, в основном, не волнует, насколько популярен Lisp. Я использую Lisp не для того, чтобы набрать больше очков в соревновании по популярности. Я использую Lisp, потому что это лучший язык программирования, который я знаю. Я не думаю, что с Лиспом что-то особенно или серьезно не так. Возможно, на данный момент он не обеспечивает того, что некоторые люди ожидают от языка программирования (например, бесплатную кроссплатформенную реализацию со всеми библиотеками, которые могут вам понадобиться). Произойдет ли это когда-нибудь, я не знаю, и меня это не заботит (хотя я уважаю, что другие могут волноваться по этому поводу). Думаю, я знаю, что некоторым людям, которые хотят, чтобы это произошло, придется запачкать руки и просто сделать это. Никакие сетования не могут волшебным образом создать какие-либо библиотеки.

Подробнее..

Частичное применение и каррирование функций в Лиспе

30.09.2020 10:08:50 | Автор: admin
Одно из известных преимуществ Лиспа над другими языками программирования состоит в том, что в Лиспе проще, чем где бы то ни было, реализуются различные новые механизмы, появляющиеся в современных языках программирования. Причин тому несколько: это и гомоиконность Лиспа (единая форма представления программ и данных) и уникальная по своим возможностям система макро. В общем, Лисп не зря называют программируемым языком программирования.

В этой небольшой заметке мы рассмотрим, как можно реализовать в Лиспе такие, весьма популярные ныне программные механизмы, как частичное применение и каррирование функций. При этом я буду использовать свою реализацию Homelisp (это чистый интерпретатор Лиспа с некоторыми дополнительными возможностями).
Вероятно, использование частичного применения в Common Lisp будет не очень простым (в связи с тем, что для вызова вычисляемого функционального объекта нужно использовать funcall/apply); в Scheme дело должно обстоять проще. В ближайшее время я планирую опубликовать новую версию HomeLisp, в котором для вызова вычисляемого функционального объекта не требуется funcall/apply. В тех случаях, когда поведение кода отличается, я буду это подчёркивать.

Частичное применение и каррирование это строгие математические операции. Но мы рассмотрим их на пальцах, без обращения к лямбда-исчислению и комбинаторной логике.

Частичное применение функции f это получение из функции f новой функции f', которая уже приняла заданные аргументы, и готова принять остальные. Для чего нужно частичное применение? Например, для того, чтобы из функции можно было вернуть функциональное значение.

Рассмотрим частичное применение на простом примере. Пусть функция f задана формулой:

f(x,y,z)=x+y**2+z**3

тогда частичное применение этой функции с аргументами x=1 и y=2 должно породить функцию:

f'(z) = 1+4+z**3 = 5+z**3

В языке Хаскелл частичное применение ничего не стоит программисту:

Prelude> f x y z = x+y**2+z**3  -- задаем функциюf :: Floating a => a -> a -> a -> aPrelude> f 1 2 3 -- проверим...32.0 -- верно!it :: Floating a => aPrelude> f' = f 1 2  -- частично применяем её при x=1 y=2 и сохраняем новую функцию f'f' :: Floating a => a -> aPrelude> f' 3 -- функция f' принимает один аргумент32.0 -- и даёт верный результатit :: Floating a => a

Однако, в Лиспе такая попытка приведет к неудаче:
(defun f (x y z) (+ x (* y y) (* z z z))) ;; Определяем функцию==> F(f 1 2 3) ;; Проверяем работоспособность==> 32 ;; Верно(f 1 2) ;; Пробуем задать не все аргументы...PairLis: Слишком мало фактических параметров Функция: FФормальные  параметры: (X Y Z)Фактические параметры: (1 2)==> ERRSTATE

Конечно, в Лиспе существует механизм создания функций с любым числом аргументов (конструкция &rest); можно создать функцию, которая будет принимать два или три (или десять) параметров:
(defun s (&rest x) ;; неопределенное к-во параметров собирается в список x  (apply '+ x)) ;; и этот список суммируется==> S(s 1 2) ;; два параметра==> 3(s 1 2 3) ;; три параметра==> 6

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

Посмотрим, как можно реализовать на Лиспе механизм частичного применения функции. И поможет нам в этом да-да, аппарат анонимных функций (lambda). Некоторые программисты думают, что анонимные функции нужны только для экономии имен (мол, их место во всяких stream-map-filter-reduce для того, чтобы выполнить короткое действие над элементом последовательности). На самом же деле анонимные функции способны на гораздо большее, в чем мы сейчас и убедимся.

Начнем с того, что рассмотрим, как функция может вернуть другую функцию как результат. В Лиспе это очень просто:
(defun func-gen (x)   (lambda (y) (+ x (* y y))))==> FUNC-GEN(func-gen 5)==> (CLOSURE (Y) ((+ X (* Y Y))) ((X 5)))

Как видим, функция возвращает замыкание, в котором значение свободной переменной x зафиксировано (равно 5). Результат функции можно вызвать как функцию. Для этого в Common Lisp и HomeLisp (с редакцией ядра <= 15.53) придется использовать funcall:
(funcall (func-gen 5) 7)==> 54

Теперь понятно, как можно действовать, если мы хотим взять функцию f от n аргументов и одно значение x, а в результате получить функцию от (n-1) аргумента. Обозначим список формальных параметров нашей функции через plist. Тогда все, что нужно сделать, это построить вот такое лямбда-выражение:
(lambda (хвост-plist) (apply f (cons x хвост-plist)))

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

Значит, для частичного применения функции нужно на базе этой функции построить лямбда-выражение, у которого аргументов будет на единицу меньше, а аргумент, заданный при частичном применении, будет учтен во внутреннем вызове нашей функции в теле лямбда-выражения.
Как это реализовать? Несложно В HomeLisp есть функция getd, которая обеспечивает доступ к определяющему выражению функции или макро:
(defun g (x y z) (+ x (* x y) (* x y z)))==> G(getd 'g)==> (EXPR (X Y Z) (+ X (* X Y) (* X Y Z)))

Как видим, getd возвращает определяющее выражение функции, в котором вместо лямбда находится специальный атом EXPR. Мы можем взять список параметров нашей функции (второй элемент результата) и построить лямбда-выражение, параметрами которого будет хвост исходного списка параметров, а в теле лямбда-выражения мы вызовем исходную функцию с полным списком параметров.
(defun part-apply (f a)  (let* ((plist (cadr (getd f))) ;; исходный список параметров         (rlist (cdr plist))     ;; список параметров без первого          (clist (cons a rlist))) ;; список для вызова с заданным a        `(lambda ,rlist (apply (quote ,f) (list ,@clist)))))

Из приведенного кода легко понять, что plist это исходный список функции f, которую мы хотим применить частично. rlist исходный список без первого элемента, а clist полный список параметров, в котором первый элемент заменен на значение x. Конкретно, для функции g, приведенной выше plist = (x y z), rlist=(y z), а clist=(a y z). Проверим теперь, как работает частичное применение:
(part-apply 'g 111)==> (LAMBDA (Y Z) (APPLY (QUOTE G) (LIST 111 Y Z)))

Можно убедиться, что это именно то, что и планировалось: part-apply вернула новую функцию, с числом аргументов, на единицу меньшим. Если эту новую функцию вызвать с параметрами y и z, то результат будет в точности такой же, как и вызов исходной функции g с тремя аргументами: 111 y и z:
(g 111 1 2)==> 444 ;; исходный результат(funcall (part-apply 'g 111) 1 2) ;; вызов "по-коммон-лисповски"==> 444 ((part-apply 'g 111) 1 2) ;; вызов "по-схемному"==> 444


Ниже я (для краткости) не буду указывать funcall. В следующем ядре HomeLisp будет изменена схема вычисления функций станет доступным схемный синтаксис.

Пойдем дальше. Теперь возникнет естественное желание повторно применить результат повторного применения. Это оказывается уже совсем простым делом ведь результат частичного применения это лямбда-выражение, а оно устроено почти идентично с результатом, который возвращает getd. Список параметров лямбда-выражения это второй элемент списка. Все эти соображения позволяют построить окончательное решение поставленной задачи:
(defun part-apply (f a)  (cond ((and (atom f) (member 'expr (proplist f))) ;; *** функция ***         (let* ((plist (cadr (getd f))) ;; исходный список параметров                (rlist (cdr plist))          ;; список параметров без первого                 (clist (cons a rlist)))    ;; список для вызова с заданным a                `(lambda ,rlist (apply (quote ,f) (list ,@clist)))))        ((eq 'lambda (car f))   ;; *** лямбда-выражение ***         (let* ((plist (cadr f))        ;; исходный список параметров                (rlist (cdr plist))       ;; список параметров без первого                 (clist (cons x rlist))) ;; список для вызова с заданным x               `(lambda ,rlist (apply (quote ,f) (list ,@clist)))))        (t (raiseerror "part-apply: неверен функциональный аргумент"))))

Здесь добавлен анализ первого параметра: если это атом, то он должен представлять функцию (типа EXPR); если первый параметр не является ни правильным атомом, ни лямбда-выражением, то возбуждается состояние ошибки. Код, разумеется, можно было бы еще подсократить, две почти идентичные ветви оставлены для наглядности. Посмотрим теперь, на что способна эта функция:
(part-apply (part-apply 'g 1) 2) ;; двукратное применение возвращает функцию одного аргумента==> (LAMBDA (Z) (APPLY (QUOTE (LAMBDA (Y Z) (APPLY (QUOTE G) (LIST 1 Y Z)))) (LIST 2 Z)))((part-apply (part-apply 'g 1) 2) 3) ;; ее можно вызвать и получить верный результат==> 9(part-apply (part-apply (part-apply 'g 111) 1) 2) ;; трехкратное применение возвратит безаргументную функцию==> (LAMBDA NIL (APPLY (QUOTE (LAMBDA (Z) (APPLY (QUOTE (LAMBDA (Y Z) (APPLY (QUOTE G) (LIST 111 Y Z)))) (LIST 1 Z)))) (LIST 2)))((part-apply (part-apply (part-apply 'g 111) 1) 2)) ;; ее тоже можно вызвать...==> 444(setq u (part-apply 'g 111)) ;; результат частичного применения можно присвоить переменной==> (LAMBDA (Y Z) (APPLY (QUOTE G) (LIST 111 Y Z)));; Создана глобальная переменная U(part-apply u 1) ;; частичное применение можно продолжить==> (LAMBDA (Z) (APPLY (QUOTE (LAMBDA (Y Z) (APPLY (QUOTE G) (LIST 111 Y Z)))) (LIST 1 Z)))((part-apply u 1) 2) ;; а можно вызвать==> 444


Теперь займемся каррированием. Каррированная функция, принимая недостаточное число аргументов, возвращает функцию, способную обработать остальные. Главное предназначение каррирования это как раз обеспечение частичного применения. Мы зашли с другого конца: рассмотрим теперь, как можно реализовать каррирование, если имеется частичное применение.

Пусть дана функция g нескольких аргументов. Мы построим ее каррированный вариант под другим именем !g. Суть построения будет такой: функция !g будет примать неопределенное число аргументов. После вызова она должна проверить количество переданных аргументов. Если это количество равно количеству аргументов исходной функции g, то следует из передать на вход g. Если количество аргументов больше, чем способна принять g, то следует возбудить состояние ошибки. А вот если количество аргументов меньше, чем у функции g, то да-да нужно выполнить последовательное частичное применение. Результат этого применения вернуть.

В данном случае удобно использовать макро. Код с комментариями приведен ниже:

(defmacro curry (f)   (let* ((parmlist (cadr (getd f))) ;; список параметров f           (body      (cddr (getd f))) ;; тело функции f   (lp          (length parmlist)) ;; длина списка параметров f   (cf          (implode (cons '! (explode f))))) ;; новое имя для результата каррирования`(defun ,cf (&rest x)   (let ((lx (length x))) ;; длина актуального списка параметров        (cond  ((= lx ,lp) ;; полное применение                    (let ((e `(lambda ,parmlist ,@body)))                          (apply e x)))                  ((> lx ,lp) ;; параметров слишком много                          (raiseerror "curry: Слишком много фактических параметров"))                  (t (let ((tmp nil)) ;; здесь будет результат                (iter (for a in x) ;; частично применяем заданные параметры    (setq tmp (if (null tmp) (part-apply (quote ,f) a) (part-apply tmp a))))                       tmp)))))))


Здесь следует прокомментировать построение нового имени функции. Для этого используются функции HomeLisp explode, которая из атома строит список составляющих его символов, и implode, которая сжимает символы списка в один, порождая новый атом.

Проверим теперь наш макро в деле:
(curry g) ;; каррируем g==> !G ;; каррированный вариант(!g 1 2 3) ;; при обычном вызове==> 9 ;; ведет себя как g(!g 1 2) ;; если аргументов недостаточно - вернет функцию для обработки остальных==> (LAMBDA (Z) (APPLY (QUOTE (LAMBDA (Y Z) (APPLY (QUOTE G) (LIST 1 Y Z)))) (LIST 2 Z)));; Можно сразу и вычислить результат:((!g 1 2) 3) ;; остался один аргумент==> 9((!g 1) 2 3) ;; осталось два аргумента==> 9(!g 1 2 3 4) ;; лишние аргументы вызовут ошибкуcurry: Слишком много фактических параметров==> ERRSTATE


Каррирование у нас выполнено без дополнительного контроля. И мы не реализовали каррирования лямбда-выражение. При желании все это можно сделать

Вот так можно без большого напряжения сил реализовать в Лиспе частичное применение функций и каррирование. Лисп замечательный язык!

Спасибо за внимание.
Подробнее..

Из песочницы Итоги двух лет изучения Structure and Interpretation of Computer Programs

19.11.2020 12:06:35 | Автор: admin


Оригинал опубликован в моём блоге 11.07.20. Если я правильно понял, это не проблема.

Я считаю, что разработка ПО в значительной степени заключается в программировании на псевдокоде. Если ты представил псевдокод, то перевести его на Python, C, что угодно не проблема. Основная сложность заключается вот в этой концептуальной деятельности, а не в кодировании. Нужно знать, как подходить к тем или иным вопросам. Модульность, абстракция. Гибкость, надёжность, простота. Шаблоны проектирования. Юнит-тестирование. Ю ноу.

Есть на свете курс Структура и Интерпретация Компьютерных Программ (далее СИКП), который позиционируется как введение в Computer Science и ранее использовался в MIT для обучения первокурсников. Два года назад я с удовольствием одолел курс лекций по нему и взялся за книгу. Сначала расскажу о хорошем.

Текст повествует о штуках весьма далёких от моей ежедневной работы и позволил мне по-новому взглянуть на программирование. Функциональщина это целый мир, живущий по своим законам. Язык Лисп очень отличается от привычного мне языка Си бешеной гибкостью за счёт слабой типизации, автоматического управления памятью, возможности переопределения чего угодно во время выполнения. У меня сформировалась более разностороннее представление о том, как в принципе можно решать разные задачи. Говоря шахматным языком, я сильно пополнил свой репертуар домашних заготовок, которые пригождаются в работе (пусть и не каждый день). Упражнения заставляли мой мозг работать (временами очень интенсивно), переосмысливать и систематизировать ранее полученные знания. В общем и целом изучение СИКП сделало меня более хорошим разработчиком, расширило мой кругозор. Уверен, я стал смотреть на разные вещи более системным и зрелым взглядом.

Книга постоянно толкала на размышления, за это ей низкий поклон. Я глубоко осознал вещи, которые вроде бы всем известны, но которые поэтому все ленятся упоминать. Например, что всё ПО сначала делается простым, а потом неизбежно усложняется ради повышения производительности. Пользователю-то плевать, сколько строк исходного кода внутри, а вот скорость имеет значение.

А что там насчёт конкретных эффектов для работы? Я стал лучше видеть недочёты во время code review (в первую очередь, своего же кода). Полюбил маленькие функции, желательно как можно более общего вида. Стал практиковать аккуратное и уместное использование макросов иногда на Си можно осторожно сделать что-то не по правилам, и от этого все только победят. Опыт, полученный при решении упражнений из книги, помог мне в некоторых задачах по работе.

Но это одна сторона медали. Другая заключается в том, что подход этого курса к обучению можно выразить английским фразеологизмом sink or swim. Перед тобой стоит перекладина, рядом с ней задание: подтянуться 10 раз. В принципе, этого достаточно для выполнения задачи, но нельзя сказать, что такой подход приятен. Я бы сказал, он весьма выматывает! Тебя бросают в бой полуподготовленного, и часть материала ты познаёшь не на объяснениях, а на своих ошибках. Наверное, это допустимый способ обучения высокомотивированных людей, но меня-лентяя он порядком выжал. Я с трудом терпел его на протяжении 3 глав из 5 (порой я делал паузы на несколько месяцев!), сделал упражнения в них от начала и до конца, но кажется, моё терпение исчерпано.

Например, в книге нет ни слова о том, как организовать свой рабочий процесс. Нет даже приблизительного рассмотрения таких понятий, как отладка (она здесь специфическая), IDE (они здесь специфические), юнит-тесты, разбиение на файлы для повторного использования. Имеются фрагменты, где разрабатывается некая сложная система, которая будет целиком готова лишь к концу главы, а задания появляются после каждого пункта текста. Т.е. строго говоря, прочитав до страницы N, ты в ряде случаев не можешь решить задачу с этой страницы, не утащив код с последующих страниц. Код нужно тащить аккуратно, ибо в примечаниях могут обсуждаться неочевидные тонкости, а порой какой-то код приводится в качестве примера неработающей идеи. Это раздражает! Да, это прям как в реальной жизни надо самому доопределять задачу, искать что-то в интернетах, но блин Этожучебник! Я наедаюсь непростыми задачами на работе, и может, авторам стоило более педантично подойти к тексту? Ладно я, профессиональный погромист с быстрым доступом в интернеты, а как было первокурснику MIT в восьмидесятых? Уверен, несладко

Подчеркну главные плюсы книги: она позволяет получить личный опыт, набить свои шишки, подумать над сложными проблемами в общем виде. С ними непосредственно связаны минусы: она сложная и зачастую даёт тебе мало подсказок для понимания чего-то. Например, если ты имеешь какой-то боевой опыт, то знаешь, что код без юнит-тестов нельзя назвать решением, но книга тебе об этом не скажет. Надо самому до этого дойти! А как ты думал? Ну или вру, книга об этом скажет, но максимально садистским способом. У тебя будет следующее задание, опирающееся на предыдущее (такое там сплошь и рядом). Если у тебя раньше заработал один тестовый кейс и ты решил Отлично, едем дальше!, то за поворотом тебя ждёт счастливая отладка решений сразу двух заданий. Наверное, когда это произойдёт несколько раз, ты поймёшь, что делаешь что-то не так. Главное, чтобы в такие моменты ты не бросал курс, а разбирался, тогда всё будет хорошо!

Ещё одна раздражающая черта текста: задания (опять же, как и в реальной жизни) порой недостаточно хорошо определены. Я на днях делал упражнение, за полчаса набросал решение, стал перечитывать формулировку задачи. Оказалось, что если рассуждать педантично, то я выполнил его на 95%, затратив примерно 40% усилий. Большинство чуваков, с которыми я сверялся, сделали так же. Один сделал полноценно, но использовал хак из другого интерпретатора Лиспа. Я огорчился и плюнул, потеряв мотивацию продолжать в ближайшее время. Ещё раз проговорю суть проблемы: есть задания, в которых всё решается просто и логично, но только если не быть к себе строгим. Так и в реальной жизни, я понимаю, но у меня были другие ожидания от учебника. Когда делаешь упражнение в свободное время и сам себя проверяешь, то хочется решить проблему на 100%, а не достаточно хорошо для текущей итерации.

Проблема с юнит-тестами вообще-то того же рода. Иногда нужно неслабо запотеть и подумать, чтобы просто внедрить их в систему. Я-то знаю, что без них никуда, но более простые ребята просто набрасывают решения без проверки и идут дальше! Чем ты строже, внимательнее, опытнее, тем сложнее для тебя становятся задания. Иногда просто в разы! Это демотивирует, потому что тут, в отличие от работы, за это не хвалят и не платят, а итеративный подход плохо применим. Знания и умения, полезные в реальной жизни, больно бьют по рукам при решении студенческих задачек!

Стоит сказать, что в книге много математики. Решая упражнения, я понял красоту и силу этой науки, но порой мне было тяжело именно из-за этих специфических вопросов, лишь косвенно касающихся решаемых задач. Просто авторы решили что-то показать на примере скажем интегрирования, вот ты и вспоминай да ботай!

В общем и целом, я не жалею, что вписался в эту авантюру, она была для меня полезной. Тем не менее, другим людям я рекомендую поискать что-то получше. Например, на основе СИКП с учётом его ошибок (так говорят, я не проверял) недавно был сделан курс How to Design Programs. Полагаю, стоило и мне на него позариться, но время уже не отмотаешь.

P.S. Замечательную рецензию на СИКП написал Питер Норвиг.
Подробнее..

Перевод Анонсирован Scheme Workshop 2021

13.04.2021 10:07:06 | Автор: admin

Этот пост представляет собой перевод анонса Международной Научно-Прикладной конференции Scheme Workshop 2021.

Для тех, кто не ходит под кат:

  • Тема конференции -- Lisp, Scheme, Emacs, и другие родственные языки, а также преподавание программирования.

  • Приём и рецензирование докладов продлится до 26 июня.

  • Сама конференция состоится 27 августа 2021 года, одновременно с Международной Конференцией по Функциональному Программированию.

  • Допускаются как научные доклады, так и практические отчёты, и обзоры.

Перевод анонса. (Call for Papers)

Объявлена подача заявок на Международную Конференцию по Функциональному Программированию и Языку Scheme.

На конференцию приветствуется подача докладов, отчётов и статей о новых научных результатах, практическом опыте их применения в индустрии и образовании, и даже творческое переосмысление старых идей. Приветствуется труды, посвящённые языкам, в какой-либо степени родственных Scheme: как строго подчиняющимся стандартам серии RnRS, так и более вольно их трактующим, но всё ещё считающих себя Scheme; а также иным диалектам Lisp, Racket, Common Lisp, иным функциональным языкам, поддерживающим замыкания и/или макросы (в том числе в качестве расширений), например, Dylan, ECMAScript, Hop, Lua, Scala, Rust... Элегантность статьи и содержательная ценность имеют больший вес при принятии решения о принятии, чем конкретный синтаксис примеров.

Конкретные темы включают (но не ограничиваются):

  • Взаимодествие с разработчиком: среды разработки, отладка, тестирование и рефакторинг

  • Реализация: интерпретаторы, компиляторы, инструменты, сборка мусора, профилирование и бенчмарки

  • Средства расширения: макросы и их гигиена, доменно-специфичные языки, рефлекшен и то, как расширения влияют на взаимодействие системы с программистом

  • Средства языковой выразительности: средства управления, модуляризация, свободный и параметрический полиморфизмы, типы, аспекты, модели владения, параллелизация, распределённые вычисления, недетерминированные вычисления, вероятностное программирование, и иные парадигмы программирования

  • Интеграция: сборочный инструментарий, развётывание, взаимодействие с другими языками и системами

  • Формальная семантика: теория, анализ и преобразования, частичное выполнение

  • Человеческий фактор: прошлое, настоящее и будущее, история, эволюция и социология языка, его стандартов и диалектов

  • Образование: подходы, отчёты и программы

  • Приложения: промышленные приложения

  • Искусство программирования: элегантные и педагогичные примеры применения Scheme

Даты:

  • Финальная дата подачи докладов 26 июня 2021.

  • Авторы будут уведомлены о прохождении рецензирования 12 июля 2021.

  • Финальные версии докладов (после рецензирования), должны быть предоставлены 21 июля 2021.

  • Конференция будет проводиться онлайн, 27 августа 2021.

Все даты указаны в часовом поясе (23:59 UTC-12) "в любой точке планеты".

Подача докладов

Доклады должны использовать формат acmart, подформат sigplan. Подача осуществляется в PDF, допускающем печать в чёрно-белом формате на бумаге US Letter. Шаблоны для Microsoft Word и LaTeX доступны по адресу:

http://www.sigplan.org/Resources/Author/

Этот формат согласуется с прочими ACM-конференциями, включая ICFP, которая проходит одновременно со Scheme Workshop. Рекомендуется при подаче заявки включить опцию "review", это позволят нумеровать строки автоматически и упрощает рецензирование.

Приветствуются любые виды докладов, включая традиционные статьи, технические отчёты, и блиц-доклады. Статьи и отчёты обычно занимают 10-24 страницы "нового" ACM SIGPLAN, свёрстанного в одну колонку. (Для сравнения, это примерно 5-12 страниц "старого", двухколоночного ACM SIGPLAN 9pt). Анонсы блиц-докладов ограничены в объёме 192 словами. На каждую статью и отчёт выделяется 25 минут, включая вопросы докладчику. На каждый блиц-доклад выделяется 5 минут, а также 5 минут на вопросы докладчику.

Данные ограничения не включают список литературы и прочие приложения. Приложения не ограничены в размере, но доклады должны быть понимаемы без них; также приложения могут быть оставлены без рецензирования.

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

Труды конференции будут опубликованы в формате "Технический Отчёт" Северо-Восточного Университета (США, NorthEastern University), а также на сервере препринтов arXiv.org.

Презентация доклада на конференции не ставит себе целью заменить публикацию статьи (усовершенствованной редакции) в научном журнале или научной конференции более высокого уровня.

Процесс рецензирования

На конференции Scheme 2021 будет применяться метод lightweight-double-blind (облегчённого двойного слепого) рецензирования. Поданные доклады не должны включать имена авторов и учреждений, и должны ссылаться на иные работы в третьем лице. (То есть, не "мы используем наш предыдущий результат...", а "мы пользуемся результатами, опубликованными Х")

Такая методика ставит своей целью помочь рецензентам оценить статью без предубеждения, но не исключить установление рецензентами авторства принципиально. Не следует во имя анонимности предпренимать какие-нибудь действия, могущие ухудшить качество подаваемой заявки или затруднить рецензирование. (Ссылки на предыдущие работы не следует опускать или анонимизировать.)

Форматирование

Статьи и отчёты должны использовать формат "acmart" с опцией "sigplan". Блиц-доклады могут быть поданы в формате обычного текста, либо как PDF-файл. Рекомендуется также использовать опции "anonymous" и "review", эти опции автоматически скрывают имя автора и включают нумерацию строк для упрощения рецензирования.

Ссылка на интерфейс подачи заявки

Будет опубликована ближе к дате подачи заявки

Подробнее..

Перевод Lisp для микроконтроллеров

07.05.2021 10:12:10 | Автор: admin


Lisp для плат Arduino, Adafruit M0/M4, Micro:bit, ESP8266/32, RISC-V и Teensy 4.x.

Новость!


ARM версия 3.6b теперь поддерживает save-image (сохранение образа) на всех платах ATSAMD21

В последнем релизе ARM uLisp, версия 3.6b, можно сохранять образ всего вашего рабочего пространства Lisp во флэш-память плат ATSAMD21, на которых не предоставляется отдельный чип DataFlash.

Таким образом, поддержкаsave-imageдобавляется к Adafruit Neo Trinkey, Adafruit Gemma M0, Adafruit Feather M0, Arduino Zero, Arduino MKRZero и Seeedstudio Xiao M0.

uLisp это версия языка программирования Lisp, специально спроектированная для работы на микроконтроллерах с ограниченным объемом ОЗУ, от Arduino Uno на основе ATmega328 до Teensy 4.0/4.1. Независимо от платформы, можно использовать ровно одну и ту же программу на uLisp.

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

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

Актуальную версию uLisp можно бесплатно скачать со страницыDownload uLisp.

Проекты uLisp



Управление NeoPixels на ассемблере


Трассировка лучей при помощи uLisp


Беджик Lisp




Матричные часы


Приложение для GPS-картографирования


Интерфейс термопары

Требования


ОЗУ: не менее 2 кбайт.

Память для хранения программ: не менее 32 кбайт.

ЭCППЗУ, флеш или cегнетоэлектрическая оперативная память (FRAM): при наличии используется для сохранения и загрузки рабочего пространства uLisp.

8/16-битные платформы


Версии uLisp для 8-битных и 16-битных платформ поддерживают целые числа в диапазоне от -32768 до 32767.

AVR-версия

AVR-версия uLisp поддерживает следующие платы:

Arduino Unoили другие карты на основе ATmega328. На ней достаточно памяти для простого приложения на uLisp с использованием коротких символьных имен. ВсеПростые примеры пойдут на Arduino Uno.

Arduino Mega 2560или другие платы на основе ATmega2560. С ними у вас будет достаточно памяти для весьма сложного приложения; см., например,Animals,Tweetmaze,Route finder иInfinite precision arithmetic.

ATmega1284.Хотя, в Arduino нет официальной платы на этой основе, ATmega1284 легко подключить к макетной плате, причем, здесь предоставляется целых 16 кбайт ОЗУ.

Платы ATmega4809. Arduino Nano Every и отладочная плата Microchip Curiosity Nano бюджетные платофрмы на основе ATmega4809.

32/64-битные платформы


Версии uLisp для 32-битных платформ поддерживают работу с целыми числами в диапазоне от 2147483647 до -2147483648, а также с 32-битными числами с плавающей точкой.

ARM

ARM-версия uLisp поддерживает следующие платы:

Arduino Zero. Эта плата основана на ядре SAMD21 ARM Cortex-M0+ и предоставляет 256 кбайт флеш-памяти и 32 кбайт ОЗУ.

Arduino MKRZero. Похожа на Arduino Zero, основана на ядре SAMD21 ARM Cortex-M0+ и предоставляет 256 кбайт флеш-памяти и 32 кбайт ОЗУ. В ней имеется гнездо для SD-карты, поэтому SD-карту можно использовать для сохранения и загрузки образов uLisp.

Платы Adafruit M0. ПлатыAdafruit Gemma M0, Adafruit ItsyBitsy M0 и Adafruit Feather M0 все основаны на микроконтроллере ATSAMD2148 MГц ARM Cortex M0+. У них схожие возможности и производительность; основные отличия между этими платами заключаются в их коэффициенте формы.

Платы Adafruit M4. Платы Adafruit Metro M4 Grand Central, Adafruit Metro M4, Adafruit ItsyBitsy M4, и Adafruit Feather M4 все основаны на микроконтроллере ATSAMD51120 MГц ARM Cortex M4.

Adafruit PyGamer и PyBadge. Adafruit PyGamer и PyBadge это портативные игровые платформы на основе микроконтроллера ATSAMD51120 MГц ARM Cortex M4, оснащенные цветным тонкопленочным дисплеем размером 160x128.

Платы Adafruit nRF52840.Adafruit CLUE и Adafruit ItsyBitsy nRF52840 обе основаны на микроконтроллере Nordic Semiconductor nRF52840 64 MГц ARM Cortex-M4,с 1 Mбайт флеш-памяти для хранения программ и 256 Кбайт ОЗУ.

BBC Micro:bit.Эта плата основана на микроконтроллере Nordic Semiconductor nRF51822 ARM Cortex-M0. Она работает на частоте 16 MГц и предоставляет 256 Кбайт флеш-памяти для программ и 16 Кбайт ОЗУ.

Maxim MAX32620FTHR.Эта плата основана на микроконтроллере Maxim MAX32620ARM Cortex-M4F, работающем на частоте 96 MГц, с 2048 Кбайт флеш-памяти и 256 Кбайт ОЗУ.

Teensy 4.0 и 4.1. Они основаны на процессоре NXP iMXRT1062 ARM M7, работающем на частоте 600 MГц с 1 Мбайт ОЗУ.

Версия ESP8266/ESP32

Версия uLisp для ESP8266/ESP32 поддерживает следующие платы:

Платы ESP8266 . Эти платы основаны на 32-битном микропроцессоре Tensilica Xtensa L106, работающем на частоте 80 MГц, с 4 Мбайт флеш-памяти и 80 Кбайт ОЗУ. В них встроена функция Wi-Fi.

Платы ESP32. Эти платы основаны на 32-битном микропроцессоре Tensilica Xtensa LX6, работающем на частоте 160 или 240MГц, с 4 Мбайт флеш-памяти и 80 Кбайт ОЗУ. В них встроена функция Wi-Fi и двухрежимный Bluetooth.

Версия RISC-V

Версия uLisp для RISC-V поддерживает следующие платы:

Платы Sipeed MAiX RISC-V. Эти платы основаны на двухъядерном 64-битном процессоре Kendryte K210 RISC-V, 400 МГц, предоставляют 8 Мбайт ОЗУ и 16 Мбайт флеш-памяти. Они схожи по производительности.

Другие платформы


Эти платы поддерживаются более ранними версиями uLisp:

Arduino Due. Эта плата основана на ядреAT91SAM3X8E ARM Cortex-M3 и предоставляет 512 Кбайт флеш-памяти, 96 Кбайт ОЗУ и часы 84 МГц.

Версия STM32

Платы STM32. Платы STM32 Maple Mini и Blue Pill основаны на процессореSTM32F103ARM Cortex-M3, работающем на частоте 72 МГц, с 128 Кбайт флеш-памяти и 20 Кбайт ОЗУ.

Версия MSP430

Версия uLisp MSP430 поддерживает следующие платы:

MSP430 F5529 LaunchPad. Она использует флеш-память для сохранения образов и предоставляет достаточно памяти для весьма сложного приложения.

MSP430 FR5969 LaunchPad. Эта версия использует cегнетоэлектрическую оперативную память (FRAM) для рабочего пространства и для сохранения образов, благодаря чему памяти у вас в распоряжении будет предостаточно.

MSP430 FR5994 LaunchPad. Эта версия использует cегнетоэлектрическую оперативную память (FRAM) для рабочего пространства и для сохранения образов, благодаря чему памяти у вас в распоряжении будет предостаточно.

MSP430 FR6989 LaunchPad. Эта версия использует cегнетоэлектрическую оперативную память (FRAM) для рабочего пространства и для сохранения образов,а также поддерживает вывод текста на встроенный ЖКИ-дисплей.

Производительность


См.Производительность.

Спецификация


В целом, этот язык является подмножеством Common Lisp, и программы на uLisp также должны работать под Common Lisp. Но обратите внимание: там одно пространство имен для функций и переменных; иными словами, нельзя использовать одно и то же имя для функции и переменной.

На 8/16-битных платформах предоставляются списки, символьные последовательности, целые числа, символы, строки (на 32-битных платформах) и потоки.

Кроме того, на 32-битных платформах предоставляются числа с плавающей точкой и массивы, в том числе, битовые массивы.

Целое число это последовательность цифр, которой может предшествовать знак + или -. На 8/16-битных платформах целые числа могут быть в диапазоне от -32768 до 32767. На 32-битных платформах целые числа могут быть в диапазоне от 2147483647 до -2147483648. Целые числа можно вводить в шестнадцатеричной, восьмеричной или двоичной системе, при помощи нотаций #x2A, #o52, или #b101010, все эти варианты равны 42.

На платформах, обладающих более чем 2 Кбайт ОЗУ поддерживаются произвольные символьные имена, определяемые пользователем. В качестве символьной может использоваться любая последовательность, не являющаяся целым числом; так, например, 12a допустимая символьная последовательность. На платформах всего с 2 Кбайт символьное имя может содержать до трех символов из множеств a-z, 0-9, или $, * или or -.

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

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

В uLisp есть сборщик мусора, работающий с применением алгоритма пометок (mark and sweep). Сборка мусора занимает менее 1 мсек на Arduino Uno или менее 3 мсек на Arduino Mega 2560 (см.Производительность).

uLisp также содержит простой редактор программ (см.Работа с редактором программ), средство трассировки и приятный принтер (см.Отладка в uLisp).

Пример


На следующем примере показано, как можно использовать uLisp.

Загрузив uLisp себе на микроконтроллерную плату, с ним можно наладить коммуникацию, вводя или вставляя команды в монитор порта или воспользовавшись последовательным терминалом. Подробнее см. Использование uLisp.

Допустим, вы подключили красный LED-индикатор к аналоговому выводу пина 9 на Arduino Uno. Затем можете ввести команду на Lisp:

(analogwrite 9 128)

чтобы установить LED в 128, что соответствует половинной яркости.

Чтобы не пришлось писать эту команду всякий раз, когда вы хотите установить красный LED, можно написать функциюred:

(defun red (x) (analogwrite 9 x))

Теперь можно добиться того же эффекта, что и выше, просто написав:

(red 128)

В обоих случаях цвет LED изменится сразу же, как только вы введете команду.

Допустим, вы используете потенциометр, который подключили к плате, чтобы варьировать напряжение на аналоговом входе A0. Можно определить функциюdim, чтобы потенциометр сам корректировал яркость LED, вот так:

(defun dim () (loop (red (/ (analogread 0) 4)))

и запустить, написав:

(dim)

Наконец, можно сохранить образ uLisp в ЭСППЗУ и указать, чтоdimдолжна выполняться при загрузке, введя:

(save-image 'dim)

После перезапуска Arduinodimбудет загружаться и выполняться автоматически.

Это простой пример, демонстрирующий, как на uLisp можно составлять сложные программы из более простых компонентов, тестируя каждый из компонентов по ходу работы.



Облачные серверы от Маклауд быстрые и безопасные.

Зарегистрируйтесь по ссылке выше или кликнув на баннер и получите 10% скидку на первый месяц аренды сервера любой конфигурации!

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru