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


Чтобы язык из коробки работал и на сервере, и в вебе, и на мобильных платформах я решил сделать компиляцию в Javascript, который по-моему мнению без шуток является одним из лучше всего спроектированных языков нашего времени и что гораздо более важно обладает мощнейшей экосистемой npm, Node.js, React и React Native.


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


=-> './database' database
=-> 'express' express

= application express ()

application.get '/'
  -> (request response) (response.sendStatus 200)

application.get '/user/:id'
  -> (request response) (response.send (database.getUserById request.params.id))

application.listen 8080
  -> () (console.log 'Application is listening on port 8080')

Ну что ж, начнем...


Шаг 1: Вырываем с корнем скобочки из Lisp с помощью индентации Python


image
Хоть этот комикс и вызывает у меня улыбку каждый раз, как я на него смотрю, я совершенно не согласен с основным его утверждением. Скобочки — это не элегантно, скобочки — это бойлерплейт.


Поэтому первым делом в своем чудесном языке я решил избавится от скобочек. Лучшим решением стала имеющая значение индентация, прямо как в Python. Возьмем, к примеру, такой кусок кода на lisp:


(* 2 (+ 1 2) (- 4 (/ 2 1)))

Конечно, это выражение можно разнести по разным строкам, но от забористости из засоряющих глаз скобочек это нас не избавляет.


(* 2
  (+ 1 2)
  (- 4 (/ 2 1)))

А теперь посмотрим, как элегантно и воздушно можно написать это же выражение на Sova с помощью имеющей значение индентации:


* 2
  + 1 2
  - 4 (/ 2 1)

То есть в Sova выражение a (b c) (d (e f)) равнозначно выражению:


a
  b c
  d
    e f

Шаг 2: Делаем язык лаконичным


Что мне не нравилось в большинстве языков программирования, так это засоренность синтаксиса ничего не значащим, но занимающим место на экране бойлерплейтом — лишними ключевыми словами, бессмысленными знаками препинания и многим другим. Даже в common lisp вместо простых и всем понятных символов часто используются слова для обозначения простейших операций, вроде того же defn.


Объявление констант


Возьмем к примеру объявление константы в Javascript:


const a = 1

Sova — язык исключительно функциональный и в нем все переменные иммутабельны, поэтому не нужно указывать дополнительное ключевое слово const, а пишется все просто:


= a 1

Функции


Основным элементом любого языка являются функции. Вот так минималистично они выглядят в Sova:


= addOne -> number
  + number 1

= doubleAndAddOne -> number
  = doubled (* number 2)
  addOne doubled

console.log (doubleAndAddOne 2) 

Как и в любых функциональных языках последнее выражение в теле функции является возвращаемым. То есть код выше в скомпилированном JavaScript будет выглядеть как:


const addOne = number => {
  return number + 1
}
const doubleAndAddOne = number => {
  const doubled = number * 2
  return addOne(doubled)
}
console.log(doubleAndAddOne(2))

Сравнения и условия


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


console.log
  ? true 1 0

console.log
  ? (> 2 1) 'Greater' 'Less'

console.log
  ? (> 2 1)
    ? (> 1 2) 'x' 'y'
    'z'

А вот тут например в функции checkNumber мы возвращаем значения по условию:


= checkNumber -> number
  ? (=== number 1) (<- 'One')
  ? (=== number 2) (<- 'Two')
  ? (<= number 9) (<- 'From three to nine')
  'Ten or more'

console.log (checkNumber 1)
console.log (checkNumber 4)
console.log (checkNumber 11)

В скомпилированном JavaScipt это выглядит как:


const checkNumber = number => {
    if (number === 1) return 'One'
    if (number === 2) return 'Two'
    if (number <= 9) return 'From three to nine'
    return 'Ten or more'
}
console.log(checkNumber(1))
console.log(checkNumber(4))
console.log(checkNumber(11))

Коллекции


Array


Основной коллекцией любого языка является массив. Вот так объявление и деконструкция массива выглядят в Sova:


= list | 1 2 3 4

console.log list
console.log
  list.map (-> x (+ x 1))

= (| first second) list

console.log first
console.log second

В скомпилированном JavaScript это будет выглядеть как:


const list = [1, 2, 3, 4]
console.log(list)
console.log(list.map(x => x + 1))
const [first, second] = list
console.log(first)
console.log(second)

Object


Второй самой важной коллекцией является хешмапа. В Sova объявление и деконструкция мапы выглядит так:


= map :
  a 1
  b 2
  c :
    d 3
    e 4
  f 'Hello'

console.log map

= (: a (c (: d e))) map

console.log a
console.log d
console.log e

В скомпилированном JavaScript это выглядит так:


const map = { a: 1, b: 2, c: { d: 3, e: 4 }, f: 'Hello' }
console.log(map)
const { a, c: { d, e }} = map
console.log(a)
console.log(d)
console.log(e)

Если мы хотим вызвать у объекта метод, то есть два способа это сделать. Мы можем вызвать его как object.method parameter1 parameter2 либо как .method object parameter1 parameter2. Второй способ позволяет нам создавать цепь вызовов методов.


Импорт и экспорт модулей


Импорт


Импортировать в Sova код можно модули как из других .sv файлов, так и из .js файлов. Например, в данном примере, импортируются два модуля — data/index.js и handler/index.sv:


=-> './data' (: greeting name)
=-> './handler' handle

handle greeting name

В скомпилированном JavaScript это выглядит так:


const { greeting, name } = require('./data')
const handle = require('./handler')
handle(greeting, name)

Импорт как JavaScript, так и Sova модулей дает возможность по чуть-чуть внедрять Sova в существующий Javascript проект.


Экспорт


В данном примере, из модуля экспортируется функция:


<-= -> (greeting name)
  console.log greeting
  console.log name

В скомпилированном JavaScript это выглядит так:


module.exports = (greeting, name) => {
    console.log(greeting)
    console.log(name)
}

Примеры использования


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


=-> 'lodash' _

= people |
  : (name 'Alice') (age 24)
  : (name 'Bob') (age 15)
  : (name 'Chris') (age 46)
  : (name 'Daniel') (age 35)
  : (name 'Elisabeth') (age 29)
  : (name 'Fred') (age 52)

= averageAge /
  .reduce (.map people (-> man man.age))
    -> (x y) (+ x y)
    0
  .length people

= manWithClosestToAverageAge _.minBy
  .map people (-> man (: (name man.name) (distance (Math.abs (- averageAge man.age)))))
  'distance'

console.log averageAge
console.log manWithClosestToAverageAge.name

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


=-> 'react' React
=-> 'react-dom' ReactDOM
=-> './styles' styles

= (: createElement:e) React

= App -> ((: name))
  e 'div' (: (style styles.container))
    e 'div' (: (style styles.hello)) 'Hello'
    e 'div' (: (style styles.name)) name

ReactDOM.render (e App (: (name 'John'))) (document.getElementById 'root')

Так же в репозитории есть примеры Express-сервера и React Native приложения под мобильные платформы.


Заключение


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


  • простота и мощь Lisp
  • чистота индентации Python
  • рантайм и экосистема JavaScript

Код компилятора с примерами использования языка лежит тут https://github.com/sergeyshpadyrev/sova. Буду рад увидеть звезды на репозитории от всех тех, кому понравилась концепция языка и кто хотел бы, чтобы работа над ним продолжилась. Но сразу предупрежу, что пока что это исключительно proof of concept, и даже поиграться с языком из-за отсутствия документации и некоторых возможностей крайне трудно. Например, в языке пока что отсутствует обработка исключений, классы и другие необходимые вещи. И под Windows запустить его вряд ли получится.


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

Комментарии (101)


  1. vlreshet
    20.05.2019 09:52
    +3

    *Автор*

    Хочу сделать лаконичный, простой, красноречивый язык
    *Тоже автор*
    ? (=== number 1) (< — 'One')
    <-= -> (greeting name)
    (-> x (+ x 1))


    Ну правда, я чего-то не понимаю, или в какой-то вселенной
    ? (=== number 2) (< — 'Two')
    читается действительно проще и удобнее чем
    if (number === 2) return 'Two'
    ?


    1. alexesDev
      20.05.2019 10:00

      Есть ещё более читаемые варианты в языках типа ruby

      return 'Two' if number == 2
      return 'Two' if number.eql? 2

      hakell
      fn :: Int -> String -- необязательно
      fn 2 = 'Two'
      fn _ = 'Others'


      1. dom1n1k
        20.05.2019 16:38
        +1

        Чем перевёрнутое с ног на голову условие удобнее?
        Если A то B — естественный порядок.
        B если A — странный.


        1. lair
          20.05.2019 16:48

          Да оба они, на самом деле, "естественны".


        1. alexesDev
          20.05.2019 16:49

          Может буть чуть чуть. Но если развернуть целиком, то такая запись совсем обычная.
          B только если A


          1. dom1n1k
            20.05.2019 21:10

            Естественно сначала понять ситуацию, а уже потом действие в ней.


      1. v_m_smith
        20.05.2019 17:53

        clojure


        (cond
            (= n 1) 'One'
            (= n 2) 'Two'
            (<= n 9) 'From three to nine'
            :else 'Ten or more'))</source>


        1. zagayevskiy
          20.05.2019 20:39

          Заменить :else на T и будет просто Лисп.


    1. FreeBa
      20.05.2019 10:44

      Для лисперов обратная польская/префиксная запись проще и очевиднее класической. Это стоит учитывать.


      1. alexesDev
        20.05.2019 16:51

        Это обычная запись, если воспринимать оператор как имя функции.

        const c = +(1, 2);
        const c = sum(1, 2);

        То, что там скобки по другому устроены — особенность языка. В Haskell это
        sum :: Int -> Int -> Int
        sum a b = (+) a b

        т.е. целиком фишка языка


  1. abar
    20.05.2019 10:00
    +5

    Работа интересная, придумывать свой ЯП — это всегда здорово и хороший опыт для программиста. Без сарказма.

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

    К тому же на том же Котлине задачу «найти средний возраст записей из списка и найти наиболее близкую к среднему запись» можно решить в три строки, после чего код компилируется хоть под JS, хоть под Джаву, хоть ещё куда.


    1. staticlab
      20.05.2019 10:05

      Использовать обратную польскую нотацию

      Это не обратная нотация. Это вполне себе префиксная, как и в Лиспе. В обратной нотации было бы ещё больше ада :)


      1. abar
        20.05.2019 10:11
        +2

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


  1. staticlab
    20.05.2019 10:03

    = App -> ((: name))
      e 'div' (: (style styles.container))
        e 'div' (: (style styles.hello)) 'Hello'
        e 'div' (: (style styles.name)) name

    И то же самое в CoffeeScript:


    App = ({ name }) ->
      e 'div', style: styles.container, [
        e 'div', style: styles.hello, 'Hello'
        e 'div', style: styles.name, name
      ]


  1. prostofilya
    20.05.2019 10:08
    +2

    Если лучший язык в какой-то определённой нише ещё можно найти/создать, то лучший язык в вакууме — нет.


  1. BasicWolf
    20.05.2019 10:08

    SergioShpadi, с почином!

    Но есть несколько замечаний :)

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

    По-поводу иммутабельности — имеется ввиду иммутабельность значений? Или всего лишь иммутабельность связки символ-значение?


    1. SergioShpadi Автор
      20.05.2019 10:17

      Ссылки. Это `= a 1` компилируется в `const a = 1` Javascript-а.


    1. v_m_smith
      20.05.2019 17:41

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


  1. Guitariz
    20.05.2019 11:04

    У каждого программиста есть мечта — создать свой язык программирования.

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


  1. tundramani
    20.05.2019 11:05
    +1

    Про JS иногда говорят что это Лисп в шкуре Си

    JS — это и есть лучший в мире ЯП

    И я не понимаю, зачем усложнять си-подобный синтаксис?


    1. evocatus
      20.05.2019 14:33

      Про «JS — это LISP» здесь подробно разобрано:
      journal.stuffwithstuff.com/2013/07/18/javascript-isnt-scheme


  1. tuxi
    20.05.2019 11:17
    +2

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


    1. Zenitchik
      20.05.2019 13:18

      Но язык должен быть читаемым легко и всеми «с ходу»

      Чудес не бывает.


    1. Arlekcangp
      20.05.2019 17:05

      Прежде всего цель должна быть, которую на этом яп можно достичь проще, быстрее, более понятным способом. Тогда язык займет нишу. Вот, например, скрипты в браузере — js: интерпретируемый с динамической типизацией, прототипный ООП и элементы функциональных языков. Или параллельное программирование на серверной стороне — Go (не люблю его, но т к его все знают — привожу в качестве примера): компилируемый, строгая типизация, поддержка из коробки таких сложных абстракций как CSP. Ну очевидно, что можно писать на js на сервере и наоборот — на go в браузере. Вот только так делают отдельные извращенцы. И в обратную сторону справедливо — если язык "слишком универсален" — в нем есть все и куча лишнего одновременно. И со временем эти фичи ещё и расширяются и вступают в конфликт в конечном итоге. Учитывая количество ЯП сейчас, нет смысла делать новый, если он не решает какую то специфическую задачу, которую его предшественники решают не идеально. Ну только для обучения если.


      1. tuxi
        20.05.2019 18:00

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


        1. assembled
          21.05.2019 15:52

          ява-подобный

          Не смешите меня, где вы там ява-подобность увидели? Вы Java то хоть раз видели?
          Разработчики JavaScript просто примазались к популярному в то время бренду.


          1. tuxi
            21.05.2019 17:57

            Я на 1.1-1.3 начинал писать и на JS во времена нетскейпа. Уж позвольте не согласиться с Вами :)


            1. assembled
              21.05.2019 19:19

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


              1. tuxi
                21.05.2019 21:05

                А сначала же он был простой, с простым синтаксисом и ява-подобный. То есть читабельный.

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


                1. assembled
                  21.05.2019 21:57
                  +1

                  Возможно мне не удалось правильно распарсить ваш коммент, слова о простоте не выглядят относящимися к словам о «ява-подобии» :).

                  читаемым даже для неподготовленного человека

                  Ну, скорее для тех, кто уже знаком с каким-либо си-подобным языком.


  1. VIkrom
    20.05.2019 11:24
    +3

    У каждого программиста есть мечта — создать свой язык программирования.

    Нет.


  1. Vadem
    20.05.2019 11:46

    Пара замечаний.
    Lisp без скобочек существует. Называется Wsip.
    Кажется, что вы пожертвовали читаемостью ради лаконичности:
    <-= -> (greeting name)
    Что мешает вместо этого добавить ключевое слово export например?


  1. nothern_wind
    20.05.2019 11:55

    Мне кажется для этого проекта лучше подходит название Lipthon Script ;)


    1. assembled
      22.05.2019 13:23

      Нет же, LISI — Lots of Irriating Superfluous Indentations ;D


  1. lair
    20.05.2019 11:55

    так это засоренность синтаксиса ничего не значащим, но занимающим место на экране бойлерплейтом — лишними ключевыми словами
    [...]
    = checkNumber -> number
    ? (=== number 1) (<- 'One')
    ? (=== number 2) (<- 'Two')
    ? (<= number 9) (<- 'From three to nine')
    'Ten or more'

    Ну и зачем в этом примере слово number четыре раза?


    let checkNumber = function 
    | 1 -> "One"
    | 2 -> "Two"
    | x when x > 2 && x <= 9 -> "From three to nine"
    | _ -> "Ten or more"

    (и немедленно получаем warning "значения от нуля и вниз не покрыты")


    Ну и да, говорить о "лучшем в мире языке программирования" и вообще не упомянуть типизацию?


    1. SergioShpadi Автор
      20.05.2019 12:04
      -3

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

      Я сам получил прививку от любви к типам поработав некоторое время со Scala. Сначала мне это нравилось, но в конце концов я понял, что большую часть времени занимаюсь не разработкой, а ублажением компилятора.


      1. Guitariz
        20.05.2019 12:08
        +1

        Типизация не делает код лучше

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

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

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


        1. SergioShpadi Автор
          20.05.2019 12:16

          Никакой корреляции между статической типизацией и количеством багов нет. Вот советую почитать хороший пост на эту тему (https://ru.hexlet.io/blog/posts/the-broken-promise-of-static-typing)

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


        1. Aingis
          20.05.2019 13:14
          +3

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

          Ну, вообще-то бремя доказательство тут, наоборот, лежит на доказывании утверждения пользы типизации. И — увы! — несмотря на десятки лет исследований надёжности ПО, польза типизации не доказана. Есть практики с доказанной пользой: такие как код-ревью и тесты. Типизация к ним не относится.


          А типизация, например, ускоряет отладку (аж на этапе компиляции) и упрощает дальнейшую поддержку.

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


          1. Guitariz
            20.05.2019 13:51
            +1

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


            1. Aingis
              20.05.2019 15:24
              -6

              1. Шланг засчитан.
              2. Как только вы начнёте писать программу посложнее Hello World с динамическими структурами и рекурсией, вы быстро обнаружите, что типами это описать это очень сложно, если не невозможно. Известный факт, что некоторые подходы ФП не описываются статической типизацией.


              1. lair
                20.05.2019 15:27
                +1

                Как только вы начнёте писать программу посложнее Hello World с динамическими структурами и рекурсией, вы быстро обнаружите, что типами это описать это очень сложно

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


                Известный факт, что некоторые подходы ФП не описываются статической типизацией.

                А можно пример?


              1. Guitariz
                20.05.2019 15:35
                +3

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


                1. Aingis
                  21.05.2019 15:07

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


                  1. Guitariz
                    21.05.2019 15:13
                    -1

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


                  1. retran
                    21.05.2019 16:22

                    А на мой вопрос сможете ответить?
                    Вот этот — habr.com/en/post/451422/#comment_20176348


                    1. Guitariz
                      22.05.2019 01:42

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


              1. 0xd34df00d
                20.05.2019 16:22
                +1

                Как только вы начнёте писать программу посложнее Hello World с динамическими структурами и рекурсией

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


                Как вы это тестами докажете?


          1. 0xd34df00d
            20.05.2019 16:20
            +2

            Есть практики с доказанной пользой: такие как код-ревью и тесты. Типизация к ним не относится.

            Типизация — это такой подвид тестов. От выразительной силы типизации зависит то, какие «тесты» с её помощью вы можете написать.


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


            1. Aingis
              20.05.2019 16:29
              -3

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


              1. 0xd34df00d
                20.05.2019 16:33
                +2

                Почему?


                Если у меня есть функция sort с типом (xs : List a) -> (ys : List a ** Sorted xs ys) (или функция sort : List a -> List a и рядом sortTheorem : (xs : List a) -> Sorted xs (sort xs), это чуть более модульный подход), то она проверяет, что функция возвращает сортированный список. Без деталей реализации.


                Если у меня есть функция с типом a -> b, и b не имеет вид IO b' (и ещё пару подобных вариантов), то функция не лезет в сеть и на диск, не майнит биткоины на вашем компьютере и не утягивает ключи от биткоин-кошельков. Успехов проверить это тестами.


                И нет, на каждый чих ничего менять не надо. Зачем вам менять тип функции, если поменялась только её реализация? А внутри функции у вас никаких аннотаций типов нет, тайпчекер всё сам выводит.


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


              1. lair
                20.05.2019 16:33
                +1

                Типизация же требует изменений на каждый чих.

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


              1. Guitariz
                20.05.2019 16:39
                +1

                Нормальная типизация позволяет вам тестировать бизнес логику, а не кастовать данные (причем здесь приложение, если проверяем данные) во что угодно, считать количество переданных параметров и убеждаться, что вам пришел не null — а потом называть это тестированием.


      1. lair
        20.05.2019 12:12

        Типизация не делает код лучше

        А ничего, что у любого языка есть "типизация"? Но вы просто игнорируете этот факт, вы закрываете на его глаза — а потом немедленно вводите костыли в виде number в вашем коде.


        сильно замедляет разработку.

        … или нет. Я вот на языках со статической типизацией (типа C#) пишу быстрее, чем на языках с динамической (типа python), потому что мне проще увидеть, когда я запихиваю "не то не туда".


        На языках с динамической типизацией разработка идет в разы быстрее.

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


        1. 0xd34df00d
          20.05.2019 16:19

          А ничего, что у любого языка есть "типизация"?

          Смотря что называть типизацией.


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


          1. Guitariz
            20.05.2019 16:44

            Это вы про статическую типизацию. Само поняте типизации гораздо шире и в программировании присутствует всегда


            1. 0xd34df00d
              20.05.2019 16:48

              То есть, если я буду рассуждать исключительно в терминах пары из void* и некоторого тега, описывающего семантику значения по этому указателю, и предварять любые операции проверками этого тега, то у меня получится типизация?


              Не, ну можно так говорить, но как-то, ИМХО, неправильно называть настолько принципиально разные вещи одним термином, различая их лишь неприметным прилагательным.


              1. Guitariz
                20.05.2019 16:56

                Это прилагательное и несет в себе смысл. Сама типизация никуда не девается.
                Простой пример — для операции «1» + «1» вам все равно придется объяснить, складываете вы строки или числа. «Сам» язык программирования не выбирает, он либо приоритет имеет, либо ошибку вам выкинет. Самостоятельно «догадаться» он не в состоянии.
                Это как раз именно про типизацию в принципе.


                1. 0xd34df00d
                  20.05.2019 17:00

                  Это потому что тут перегрузка операторов есть. Если у меня будет отдельно функция addInt и отдельно concatStr, то ничего никому выбирать не придётся.


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


                  Собственно, да, хороший пример. Где типы в untyped lambda calculus?


                  1. Guitariz
                    20.05.2019 17:11

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


                    1. 0xd34df00d
                      20.05.2019 17:37

                      Не, я-то апологет статической типизации, причём, ну, очень ортодоксальный апологет.


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


                      Ну да ладно, видимо, стоит уж мне прекратить пропагандировать различение этих двух разных ситуаций.


                      Скрытый текст

                      Хотя ко мне вчера на stackoverflow чувак справедливо придрался, что я использовал термин «доказательство от противного» в неправильном контексте, так что хз.


      1. tuxi
        20.05.2019 12:45

        Собеседование на должность секретаря. Директор спрашивает:
        — Какая у вас скорость печати?
        — 100 знаков в минуту!
        — Спасибо, Вы нам не подходите! Следующая!
        — Какая у вас скорость печати?
        — 200 знаков в минуту!
        — Спасибо, Вы нам не подходите! Следующая!
        — Какая у вас скорость печати?
        — 3000 знаков в минуту!!!
        — Так много???!!!
        — Ага! Правда все время такая ерунда получается...


      1. retran
        20.05.2019 15:05
        +3

        Типизация не делает код лучше


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

        И, нет, компьютеры все еще недостаточно быстрые, чтобы все могли на это забить.


      1. 0xd34df00d
        20.05.2019 16:17
        +2

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


      1. namikiri
        21.05.2019 08:30

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


      1. GarfieldX
        22.05.2019 12:32
        +1

        Про замедление разработки из-за наличия статической типизации смешно читать. Такое ощущение, что прям очередной гений стиля «херак-херак и в продакшн». Вспоминаются всякие чудики из интернета, по словам которых они каждую свободную минуту могут монетизировать и все из себя такие крутые, что, буквально, матери подать стакан воды уже убыток. Только не понятно что они на форумах интернета забыли. Это еще больше разработку замедляет ведь :)
        Ну вот никогда за мои 15 лет опыта никакая типизация никак не влияла на скорость. Зато на скорость влияет куча говнокода после таких вот кодеров за которыми приходится разгребать авгиевы конюшни.
        Статическая типизация учит порядку в мышлении и однозначно делает код лучше. И уж точно никогда и никак не мешала, разве что генерировать говнокод. Не стоит этим прикрывать свои недостатки.
        Динамическая же типизация возникла там, где это было необходимо.


        1. fireSparrow
          22.05.2019 13:06
          -1

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


    1. SergioShpadi Автор
      20.05.2019 12:11

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


      1. lair
        20.05.2019 12:12
        +1

        Ни типизация, ни eslint, ни юнит тесты не помогают.

        Кому не помогают? Вам не помогают? Ну да, верю. Мне — помогают.


        1. Guitariz
          20.05.2019 12:19

          это все дураки придумали, наверно, или проклятые менеджеры, чтобы разводить заказчика на лишние траты. Я вот накодил и сразу в прод лью</sarkasm off>


          1. lair
            20.05.2019 12:23

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


            1. Guitariz
              20.05.2019 13:12
              +1

              По моему если автор спорит о том, что лучше — статическая или динамическая типизация, дальше конструктивно можно даже не пытаться.
              В мире приняты несколько тем, запрещенных для обсуждения — политика, религия, сексуальная ориентация.
              Для разработчиков надо сюда внести еще «динамическая или статческая типизация», «фп или ооп», «множественное или одиночное наследование».


        1. SergioShpadi Автор
          20.05.2019 12:24

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

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


          1. lair
            20.05.2019 12:25

            Ну я и говорю: вам не помогло. Это не значит, что другим не поможет.


  1. legolegs
    20.05.2019 13:04
    -2

    Наброшу:
    Как же ЯП может быть «лучшим» без статической типизации?


  1. igormich88
    20.05.2019 13:13

    Я правильно понимаю что у вас не предполагается полноценных объектов, а только хэшмапы?


    1. SergioShpadi Автор
      20.05.2019 13:32

      Эти объекты компилируются в обычные объекты JavaScript.


      1. igormich88
        20.05.2019 18:39

        В обычные хешмапы, то есть instanceof от них ждать не стоит?


  1. ruSl0n
    20.05.2019 16:37
    +1

    про кофескрипт уже шутили?


  1. v_m_smith
    20.05.2019 17:32

    если переменные иммутабельны, то почему вы продолжаете называть их переменными, а не постоянными например?


  1. v_m_smith
    20.05.2019 17:32

    Автор, а вы ClojureScript смотрели?


  1. FForth
    20.05.2019 19:32
    -1

    Автор, не смотрели при изобретении своего языка на целую группу конкатенативных языков

    и в частности Factor язык, который был изобретён разработчиком его при отказе от использования Java?


    1. assembled
      21.05.2019 16:29

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


      1. FForth
        21.05.2019 16:37

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


  1. Vahman
    20.05.2019 21:21
    +2

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

    А теперь посмотрим, как элегантно и воздушно можно написать это же выражение на Sova с помощью имеющей значение индентации:
    * 2
      + 1 2
      - 4 (/ 2 1)
    


    Думаю нужно пойти дальше, и записывать в такой манере математические статьи, и литературу. Это же прекрасно, отлично читается.
    Если честно, я надеюсь, что автор шутит. Просто после всех таких статей, и прочих, где рассказывают, например, как копипаста на go становится более изящным решением, чем generic в C#, например, я начинаю сомневаться в будущем программирования.

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


  1. Sirikid
    20.05.2019 22:02

    Таким образом, язык Sova вобрал в себя лучшее из нескольких других языков:
    • простота и мощь Lisp
    А макросы у тебя где?


  1. DexterHD
    20.05.2019 22:33
    -1

    У каждого программиста есть мечта — создать свой язык программирования.

    Нет


  1. zim32
    21.05.2019 13:16
    +1

    Нормально так, для увеличения чсв сойдёт. Я тоже думал написать язык, но во время понял что я не самый умный в этом мире.


    1. FForth
      21.05.2019 13:40

      Теперь осталось на своём языке создать уникальное ПО или технологию для оправдания сего действия.


      1. YemSalat
        22.05.2019 07:59

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


  1. assembled
    21.05.2019 14:42
    +1

    Такой синтаксис называется I-expressions, придуман давно и даже в каком-то диалекте лиспа был реализован (вроде Scheme).

    Почитайте ещё про M-expressions.


  1. GarfieldX
    21.05.2019 22:45

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


    1. 0xd34df00d
      22.05.2019 05:17

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


      1. Что, если отказаться от parametricity для зависимых типов-сумм, где первый элемент в зависимой паре — тип?
      2. Можно ли попробовать интернализировать тотальность функций и как-то формализовать это понятие, а не выносить это на уровень метаязыка?
      3. Можно ли работать с отношениями эквивалентности как-то изящнее, чем так?

      Ну это так, сходу.


      1. Sirikid
        22.05.2019 18:33

        3. Сложно воспринимать код на SO, это про сетоиды?


        1. 0xd34df00d
          22.05.2019 18:35

          Да.


          1. Sirikid
            22.05.2019 18:46

            Тогда ответ можно. Берешь HoTT и быстро вилкой путями и интервалами работаешь с этими эквивалентностями.


            1. 0xd34df00d
              22.05.2019 18:48

              Язык-то где, где это все уже готовое?


              Не кок плз, люблю видеть свои термы.


              1. Sirikid
                22.05.2019 20:25

                cubicaltt, yacctt, redtt, в Agda поддержку добавили. P.S. А ещё Arend есть.


      1. GarfieldX
        22.05.2019 19:10

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


        1. 0xd34df00d
          22.05.2019 20:10

          Именно, исключительно академический интерес.


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


  1. YemSalat
    22.05.2019 07:48

    Статья интересная, и парсер у вас довольно мило написан.
    Но сам язык в текущем виде, особой пользы не представляет нa мой взгляд. Тот же пример с экспрессом почти ничем не отличается от такого же кода на js. Как уже выше написали, чтобы язык имел шанс на востребованность — у него должна быть своя ниша. Просто новым языком (особенно с весьма спорными фичами) пользоваться никто не будет.