Мова програмування, де кожен вираз має сенс


23

За рекомендацією я відновлюю це з переповнення стека .

Нещодавно я замислювався над наступним випуском.

Розглянемо код для стандарту "Привіт, світ!" програма:

main()
{
    printf("Hello World");

}

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

main(5
{
    printf("Hello World");

}

Тепер до власне питання. Чи існує мова програмування, де кожна можлива комбінація символів - тобто кожен вираз - має сенс? Я спробував подумати про якесь рішення і придумав два:

  1. Постфікс з обмеженою кількістю змінних. По суті, всі змінні вже визначені перед тим, як написати будь-який код, і вам доведеться працювати тільки з ними. Теоретично можна, ніж виконувати довільну кількість операцій, сформувавши ланцюжок з багатьох простих програм, кожна з яких подає результати іншим. Код може бути записаний у вигляді рядів символів у позначенні постфіксу;

  2. "Postfix" зі стеком змінних. Змінні зберігаються в стеку; кожна операція бере дві змінні зверху і ставить результат на їх місце. Програма закінчується, коли вона досягне останньої операції або змінної.

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

Хтось має якусь іншу ідею, як вирішити цю проблему?


48
З огляду на компілятор , створити новий компілятор , який працює наступним чином : дане джерело , передати його в . Якщо задоволений цим і створює виконуваний файл, то це те, але якщо скаржиться, то виводить виконуваний файл, який роздруковує, компілятор приймає кожну рядок як дійсну програму. C s C C C C СCsCCСYou are a bimbo.C'
Андрій Бауер

1
BF потребує відповідних [ ]команд (За даними сторінки Wiki). Моя думка полягала в тому, щоб переглянути опдори CPU. Але навіть тоді деякі шаблони можуть спричинити проблему (наприклад, якщо опкод становить 3 біти, але у вашій програмі лише 2 біти.) За винятком цього питання, можливо, додаткові додаткові 0 біт можна думати про будь-який процесор із повний набір коду, який задовольнить претензію "кожна рядок є дійсною програмою". Може бути безглуздим, але все-таки дійсним.
Ран Г.

1
Нехай вашим обладнанням буде процесор Z-80 з 64 кб оперативної пам’яті. Напишіть компілятор, який просто копіює ASCII-кодований вихідний код у пам'ять 64k (при необхідності обрізання або нульове додавання). Цей компілятор ніколи не дає синтаксичної помилки.
Бен Кроуелл

1
@RanG. "Компілятор", який обробляє будь-який бітовий потік і виправляє його як дійсний біт об'єктного коду для даного процесора, я думаю, відповідав би вимогам ОП. Це може бути не дуже складно навіть для систем зі складними наборами інструкцій, як x86. Багато років тому я прочитав статтю про достовірність випадкових байтів як програм x86, і виявив, що x86 насправді набагато надійніший, ніж спочатку очікували автори.
otakucode

2
Без додаткових умов це питання нудне: коментар Андрія та відповідь Девіда дають "тривіальні" відповіді. Ви повинні прибити більш точно, що ви хочете.
Рафаель

Відповіді:


31

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

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

У таких речах є певний пріоритет із використанням природних мов, а не формальних мов, але це не те, що я б назвав великим полем, коли ви порівнюєте його з використанням формальних мов. Якщо ви зацікавлені в таких мовах програмування, я б шукав спільноти обробки природних мов.

Ще одне поле, на яке ви можете подивитися, - це генетика. Є надзвичайно мало генетичних послідовностей, які просто недійсні. Їх безліч, які не дуже ефективні в репродукції, але дуже мало недійсних.


1
Генетика не здається гарним прикладом. Що стосується дійсного чи недійсного, ви просто говорите про реплікацію? Тому що, звичайно, кожен рядок буде дійсною програмою для мови, якою є єдино можлива інструкція replicate this string. Це насправді не є змістовною мовою програмування, однак, як ніде поблизу Turing Complete.
тел

2
@tel: Корт, ймовірно, говорить про синтез білка через мРНК, а не про реплікацію. Практично будь-яку генетичну послідовність можна переписати і потім ввести в механізм синтезу білка: чи протеїн, який виходить, є достатньо стійким, що він уже не деградував до моменту його створення, і якщо так, чи робить це щось корисне організм, інша справа ...
Стів Джессоп

3
Генетичний код не є кодом для відтворення себе. Це (загалом) код для білка. Чи корисний білок - це часто інше питання. Звичайно, це стає цікавіше. Деякі біти "коду" в генетичній послідовності в кінцевому підсумку більше нагадують інструкцію по рядках ", що кодує кілька рядків далі - іноді слід просто ігнорувати це". Є всілякі круті "програми" клітини та віруси, написані боротьбою між собою.
Джоель

TECO - ще один приклад у реальному світі.
cjm

1
@cjm вау "API готовий не тоді, коли ви закінчили додавати все, але коли ви закінчили все виводити." Якщо ви не TECO, ви закінчите, коли у вас не вистачає символів, яким можна присвоїти значення.
Корт Аммон - Відновіть Моніку

16

Ідея універсальної машини Тьюрінга використовує саме таку "мову програмування": кодування машин Тьюрінга як натуральних чисел, представлених, наприклад, у двійкових, таких, що кожне натуральне число позначає машину Тюрінга, тобто програму. У цій мові кожен рядок нулів і одиниць - це програма.

нн

Я впевнений, що є також езотеричні мови програмування, де кожна струна є програмою; однак, якщо ви просто запитуєте список тих, я думаю, що ваше запитання тут поза темою.


13

Розширити мову програмування так, щоб кожен вираз має сенс завжди можливий, але не цікавий. Наприклад, ви можете просто присвоїти значення "нічого не робити" жодному виразу, яке мова оригіналу відкидає.

Розробка мови програмування, де кожен вираз має сенс способом "ви можете його виконати", не є особливо корисним. Хороша мова програмування - це не лише мова, на якій мавпа може набрати клавіатуру і написати дійсну програму, а та, де програміст може легко написати програму, яку вони мали намір написати. Написання дійсних програм не є складною частиною програмування: складна частина - це написання програми, яка виконує те, що від неї очікували. Відхилення явно неправильних програм дуже корисно в цьому відношенні.

Інший спосіб вирішення цього питання - це повне визначення семантики всіх можливих входів, включаючи вказівку того, який час компіляції, час завантаження або час запуску повинен генеруватися для кожного вводу, якщо такий є. Тобто, «переривання програми після друку Syntax error at line 42на стандартному потоці помилок» є частиною визначеної семантики мови. Кожен вираз "має сенс", оскільки він має визначене значення. Це корисне значення? Можливо - зрештою, якщо програма явно помиляється, її відкидання корисно.


12

Ознайомтеся з Jot , повною мовою Тьюрінга на основі комбінаторної логіки, де кожна послідовність 0 і 1 (включаючи порожню послідовність) є дійсною програмою.


2
Це не відповідь з інформатики .
Рафаель

2
@Abdulrhman Це прямо вперед для визначення біекції між бінарними рядками та натуральними числами. Таким чином, ви можете кодувати будь-яку програму як натуральне число, якщо хочете.
CodesInChaos

7
@Raphael Будь ласка, докладіть або запропонуйте покращити відповідь, я буду радий її покращити, якщо ви надасте підстави для своєї критики.
Петро Пудлак

+1, я збирався дати подібну відповідь для вигаданої мови програмування на основі натуральних чисел, але це схоже. AFAIK не існує програмування (у практичному використанні), яке має цю особливість, але можна побудувати його, використовуючи просто числа, скажімо, де кожна комбінація має значення (діють як оператори, так і операнди). Це головне
Нікос М.

8

Один приємний приклад - пробіл . У мові власне будь-яка комбінація операторів є дійсною. Операторами є пробіл, вкладка та новий рядок (конкретно "\ n"). Усі інші символи вважаються коментарями .

Ця відповідь і, власне, ваше запитання (як і вся ця веб-сторінка) є прикладами дійсних програм пробілу (хоча вони можуть не робити нічого особливо цікавого).


Я просто думав про це після публікації моєї відповіді на голову (ваша краще, оскільки це правильно), але мені цікаво - чи все-таки це порожня програма? (тобто якщо ці три символи відсутні у всьому потоці файлів). - Мовляв, якби в моїй машині були відсутні всі речі, які зробили її автомобілем, чи все-таки це була б машина?
BrainSlugs83

Це не відповідь з інформатики . (Також "кожен рядок пробілу"! = "Кожен рядок".)
Рафаель

2
@Raphael: Але всі можливі рядки (включаючи ті, що не містять пробілів) є дійсними програмами пробілу - зауважте, що будь-який символ, який не є пробілом, - це просто коментарі на мові програмування пробілів
slebetman

2
@slebetman Ви занадто буквально інтерпретували мої дужки. Я говорив про парні жетони циклу. Деякі подібні проблеми в пробілі можуть бути: чи працює повернення без попереднього дзвінка? (закодовано як [LF][Tab][LF]) Що станеться, якщо ви викладете порожній стек? Що станеться, якщо перейти до невизначеної мітки? Що станеться, якщо ви визначите дублікати міток?
CodesInChaos

7

Я хотів би звернутися до думки, яку висловили багато плакатів, що така мова була б "марною". Можливо, людині було б марно писати вручну, маючи намір вирішити якусь конкретну задачу. Однак, не дивлячись на те, що це більшість випадків використання для мов програмування, це, звичайно, не єдиний випадок використання. Приходять на думку кілька випадків використання, коли така мова корисна, і ми можемо звернутися до цих полів для прикладів таких мов.

По-перше, алюзія Корта Аммона на генетику помітна : перетворення програми у питанні (заміщення )на яке 5) може розглядатися як мутація . Цей вид маніпуляцій поширений у галузі еволюційних обчислень ; зокрема, генетичні алгоритми виконують такі перетворення на струнах , тоді як генетичне програмування перетворює програми . У будь-якому випадку ми зазвичай хочемо присвоїти значення кожній можливості, оскільки це створить найбільш компактний простір пошуку.

Генетичні алгоритми покладаються на якусь функцію оцінки рядків; якщо ми використовуємо інтерпретатор мови програмування як нашу функцію оцінювання, тоді у нас є сценарій, коли мова програмування, яка присвоює значення всім можливим рядкам. У генетичному програмуванні передбачається, що наша функція оцінювання є перекладачем мови програмування, але ми можемо обирати різні уявлення для наших програм; наприклад, багато систем працюють на абстрактних синтаксичних деревах. Якщо ми обираємо рядки як своє представлення, то ми відновимо той самий сценарій, що і з генетичними алгоритмами.

Інша ситуація, коли ми можемо бажати, щоб кожна рядок була дійсною програмою, це при перерахуванні програм. Це пов'язано з біекцією, згаданою CodesInChaos, але ми можемо з кількох причин оперувати на рядках, а не на натуральних числах:

  • Якщо в мові є якась структура, напр. ми можемо присвоїти значення підрядкам, це може бути втрачено при перекладі на натуральні числа. У цьому випадку ми можемо вважати за краще використовувати рядки для того, щоб міркувати про та перетворювати підрядки локально, а не представляти всю програму як число. Це аналогічно тому, як ми могли б вважати за краще використовувати побітові операції над int, а не арифметичними виразами, коли кожен біт має індивідуальне значення. Це в основному узагальнення еволюційного сценарію.
  • Ми можемо захотіти генерувати програми на вимогу; наприклад, ми можемо почати виконувати програму, яка повністю не визначена, і генерувати (наприклад, випадковим чином) окремі інструкції (наприклад, символи), коли / якщо вказівник інструкції досягає їх. Це поширене в алгоритмічній теорії інформації, де програма є стрічкою машин Тьюрінга, а мета - охарактеризувати поведінку випадково згенерованих програм. Наприклад, ми можемо сформулювати Solomonoff попередньо над довільними рядками як ймовірність того, що універсальна машина Тьюрінга зі випадковою стрічкою виведе цю струну.

З точки зору прикладних мов, багато еволюційних обчислювальних систем базуються на мовах стеків, як сім'я Push . Вони, як правило, дозволяють довільні потоки жетонів (які ми могли б представляти як окремі символи). Іноді (як, наприклад, приклад BrainSlugs83 Brainfuck) існують обмеження щодо балансування дужок; Однак, ми можемо пов'язати це з саморазгранічни програмами , в тому , що рядок , як [не може бути дійсною програмою , але вона є дійсним префіксом програми . Якщо ми уявляємо, що компілятор / інтерпретатор читає вихідний код із stdin, то він не відкине рядок типу [, він просто чекатиме більше введення, перш ніж продовжувати.

Такі мови, як Бінарна комбінаційна логіка та Двійковий обчислення лямбда, виникли безпосередньо поза роботою над теорією алгоритмічної інформації, наприклад. від http://tromp.github.io/cl/cl.html

Ця конструкція мінімалістичного універсального комп’ютера була мотивована моїм бажанням придумати конкретне визначення складності Колмогорова, яке вивчає випадковість окремих об’єктів.


2

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

Мова програмування, як те, про що ви запитуєте, змусить людей зрозуміти, що вони хочуть читати, а не те, що записано. Налагодження в мовах, де існує обмежений набір юридичних тверджень, де неможливо багатозначності, вже досить жорстке. Хороші мови зменшують можливі інтерпретації, наприклад, через перекладені символи чи друкарські помилки. Природні мови також відомі своєю надмірністю з тієї ж причини.


0

У Brainfuck мовою програмування , майже все можливе бінарне вираз можна інтерпретувати як програму. - Тобто, ви могли б взяти цілком хорошу програму, набрати в неї купу сміття, і вона все одно може бути складена / інтерпретована без жодних питань.

( Редагувати. Виявляється, вам потрібно відповідати квадратним дужкам, що відкриваються та закриваються, але в іншому випадку це вище.)

Це досягається цими двома простими методами:

  1. Усі команди, які він розуміє, - це один байт (у BF - це єдині символи ASCII, наприклад *).

  2. Усі персонажі, яких він не розуміє, відкидають як коментарі.

Мова програмування є Тьюрінгом повним (тобто він може робити все, що може зробити будь-яка інша мова).

*: Виявляється, не всі команди BF є єдиним байтом ASCII - тобто дужки ОБОВ'ЯЗКОВО узгоджуватись - так, що мова не відповідає першим критеріям там. - Але будь-яка мова, яка відповідає обом критеріям, відповідала б тому, чого вимагає ОП.


2
Це не тільки не дає відповіді на питання, це не відповідь інформатики .
Рафаель

1
Ви можете переосмислити мову, щоб обробити їх якось розумним чином. наприклад, вставивши достатньо кронштейнів, що відкриваються, на початку програми та закриваючи дужки в кінці програми, щоб зробити її збалансованою. Прямо вперед написати інтерпретатора, який обробляє програми так, ніби ці дужки існували, не переробляючи програму. Звичайно, запускати мозкову програму з відкриваючої дужки досить марно, оскільки вона буде ігнорувати все, аж до відповідної дужки закриття.
CodesInChaos

1
@Raphael ОП питання було "Чи існує мова програмування, де кожна можлива комбінація символів - тобто кожен вираз - має сенс?" - моя відповідь «так, ось приклад того, що наближається, і ось теорія за цим». - окрім встановлення точних правил для одного класу мов, який би відповідав вимогам ОП, я не впевнений, наскільки тут більше місця для науки . Чи можете ви навести приклад або посилання на ресурс того, що саме ви сподіваєтесь побачити тут? -- Дякую.
BrainSlugs83

2
Девід і Жилль дають відповіді з інформатики. Вони досліджують принципи і не просто кажуть: "мова X робить це (майже)". Якщо ви прочитаєте їх відповіді, то дізнаєтесь, що відповіді останньої форми теж досить нудні. Це не ваша вина, але ОП - питання (як питання інформатики) нудне; є помилкове відчуття складності.
Рафаель

Можна легко "виправити" BF, щоб будь-який рядок був прийнятий: ви просто робите вигляд, що ]в кінці джерела є достатньо символів, щоб відповідати всім незрівнянним [s, а [на початку достатньо, щоб відповідати всім незрівнянним ]. Семантика [і ]може бути легко змінена, щоб зробити їх рівнозначним цьому. (наприклад, якщо немає відповідності, ]то [просто зупиняє виконання, якщо байт у вказівнику даних дорівнює нулю. ]Просто переходить до початку програми в подібній ситуації.) Отримана мова буде Turing завершеною і приймає будь-який рядок.
Натаніель
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.