LINUX.ORG.RU

ЛОР, помоги выбрать ЯП для обучения

 , , , ,


1

3

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

Вот к каким мыслям я пришёл:

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

Не Си и не современные коммерческие языки (Java, C#, Go). Си, хотя примитивный в основе, усложнён из-за окружения, в котором используется. Современные коммерческие языки были созданы для решения проблем индустрии. Проблема общая: я хочу преподавать материал по мере нарастания сложности. Если в языке неизбежно приходится использовать классы или printf, то это затруднит объяснение (не хотелось бы слишком часто говорить «потом узнаешь для чего это нужно»), напугает студента (ему придётся писать код, используя возможности, которые он плохо понимает), создаст неправильное восприятие основ (как будто printf — это какая-то важная часть компьютера или ОС).

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

Языки, между которыми я выбираю: Pascal и Python.

Pascal устарел и денег не принесёт (обидно), но это и не является основной целью. Целью является программирование, а не современное окружение.

В частности, я не собираюсь задрачивать студента на Delphi или любой «продвинутый» диалект языка. Это противоречит цели. Я рассчитываю на то, что после должной тренировки “bare bones” нужно перейти на современный язык и это будет легко.

Важно упомянуть, что спека языка Oberon (Виртовский язык, тот же Паскаль, только упрощённый и доработанный) составляет 17 страниц.

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

Если ограничиться императивным подмножеством, без ассоциативных массивов, классов и мета-классов, list comprehensions, HOF, исключений, то выглядит как альтернатива Паскалю. Хотя меня беспокоит динамическая типизация. Типы — очень важная вещь, хотелось бы чтобы язык помог это донести, а не быть типа «ну да, это важно, но ты забей».

Это все мои мысли.

Что касается практики, то я имел несчастье наблюдать как человек впервые знакомился с программированием, изучая Java на javarush. На это было больно смотреть.

Edit: дальнейшие пояснения по теме:

  • Подробнее про то, почему я считаю, что изучение основ и Паскаль хорошо сочетаются: 1
  • Почему не Си и не ассемблер: 1 2
  • Почему Паскаль: 1 2
  • Почему не Питон: 1
  • Целевая аудитория: 1
  • Почему такая размытая аудитория: 1 2
  • Про важность иерархии: 1


Последнее исправление: kaldeon (всего исправлений: 10)
Ответ на: комментарий от ugoday

Компилятора может вообще не быть.

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

mister_VA ★★
()
Ответ на: комментарий от mister_VA

Если вы написали программу и компилятор с первого прохода не нашёл в ней ошибок, сообщите об этом системному администратору. Он исправит ошибки в компиляторе». Богатство возможностей Ады – это потуги разработчиков компилятора Ады. Но они люди и тоже могут ошибаться.

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

Учебник – это вельми специфический жанр и мало кто умеет в него.

Абсолютно и полностью с вами согласен! Также добавлю что и сам процесс обучения тоже штука очень специфическая и в него тоже мало кто умеет. Уметь что-то сделать и уметь объяснить другому человеку как это сделать - два разных умения. Также как умение программировать и умение проходить собеседования на высокооплачиваемые программистские позиции.

watchcat382
()
Ответ на: комментарий от mister_VA

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

P.S. Вас же не смущает, что программа может быть сильно статически типизированной, а в процессоре никаких типов нетути. Ну так и тут то же самое.

ugoday ★★★★★
()
Последнее исправление: ugoday (всего исправлений: 1)
Ответ на: комментарий от Ygor

ты Sicp почитай, там все начинается с: а давайте найдём квадратный корень методом рекурсии.

Это не отвечает на мой вопрос - где в работе программиста применение рекурсии именно необходимо по соображениям производительности/памяти?

попытки допустим найти число Фибоначи

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

Изрядно поскрипев мозгами я вспомнил только один из многих возможных генераторов псевдослучайных чисел. Так он уже давно написан,его готовый взять можно,причем не обязательно с использованием рекурсии. И то,если по каким-то причинам нужен вот именно «фибоначчивый»(причины придумать не смог). Но я по образованию не чистый программист,а электронщик с навыками программирования, к тому же практик. Тут у нас на форуме периодически появляются люди с теоретической базой намного покруче чем у меня. Может они увидят мой вопрос и смогут на него аргументированно ответить…

watchcat382
()
Ответ на: комментарий от ugoday

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

Собственно да, например «micropython» в микроконтроллерах. Очевидно что там не абсолютно полная реализация, тем не менее это питон. Правда не очень понимаю нафига он там нужен,но кто-то пользуется. Может тот кто в компилируемые языки с строгой типизацией не умеет?

watchcat382
()
Ответ на: комментарий от watchcat382

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

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

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 2)
Ответ на: комментарий от watchcat382

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

ugoday ★★★★★
()
Ответ на: комментарий от monk

Пайпами в шелле тоже не пользуешься? Исключительно переменными и циклами?

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

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

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

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от mister_VA

Зачем изобретать Паскаль, если он уже давно изобретён гораздо более умными человеком?!

У Паскаля есть в данном случае недостаток - у него неопределено понятие подмножества языка. То есть когда это еще Паскаль,а когда уже не паскаль,а лишь язык с паскалеподобным синтаксисом. А вот у Ады официально определенные подмножества есть - например Ravenscar и Jorvik. Это не языки,это именно кодовые имена подмножеств Ады для систем с ограниченными ресурсами. Есть еще подмножество Spark для случаев требования особо зверской надежности. К примеру когда Аду запихивают в микроконтроллеры STM32 как раз обычно подмножество Ravenscar и используют.

Есть у меня типа мечта - собрать у себя на компе комплект для разработки софта на Аде под дешевые китайские контроллеры STM32F103C8T6. Но пока что усидчивости не хватает. Хотя прецеденты таких попыток известны,к сожалению без особых подробностей как реализации так и достигнутых результатов: http://www.hrrzi.com/2017/11/ada-on-2-ebay-bluepill-board.html

watchcat382
()
Ответ на: комментарий от ugoday

умный человек решил исправить недостатки Паскаля и придумал Модулу и Оберон.

Кстати,в начале 90х,прежде чем удалось добыть компилятор Meridian ADA я пытался писать на TopSpeed Modula 2. Вполне приятный язык и компилятор. Но Ада понравилась больше.

watchcat382
()
Ответ на: комментарий от ugoday

А много вы иностранных языков знаете?

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

знания что-то не переносятся.

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

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

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

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

watchcat382
()
Ответ на: комментарий от mister_VA

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

Я бы сказал что например интерпретатор Лиспа это эмулятор функционального языка на императивном(ассемблере). Потому как Лисп-процессоров нынче нет. Хотя по слухам когда-то были. Если конечно там тоже не эмуляция была.

watchcat382
()
Ответ на: комментарий от ugoday

Ну не взлетели и не взлетели. Паскаль и сам не очень-то высоко летает последние лет пятнадцать.

А что будем считать высотой полёта? Количество проектов на гитхабе что ли? Так это лишь показатель именно что количественной популярности. Посредственных книг продается намного больше чем действительно хороших. Будем считать что Пушкин не взлетел?

Кроме того,популярность может быть обусловлена причинами,к техническим качествам языка отношения не имеющими. Загнулась фирма Borland из-за безграмотного управления,перестала поддерживать свои компиляторы и адаптировать их к новым версиям ОС - вот и Паскаль утратил популярность. Появился FreePascal - и о Паскале снова вспомнили.

watchcat382
()
Ответ на: комментарий от alysnix

рекурсия удобно применима на деревьях

Удобно применима не означает обязательна. К тому же удобство - штука очень субъективная. Я вот всю жизнь рекурсии избегал например,мне она неудобна,хотя я и понимаю как она работает.

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

А если без рекурсии написать - чем это грозит? Уточню что «рекурсивный алгоритм» это не равнозначно программе,использующей рекурсию на уровне реализации,то есть вот прямо функции сами себя вызывающие. Без этого обычно можно обойтись.

watchcat382
()
Последнее исправление: watchcat382 (всего исправлений: 1)
Ответ на: комментарий от ugoday

безразлично вообще на чём их и реализовывать. Можно и на микропитоне.

Вот именно что если безразлично на чем - то зачем на микропитоне если можно хотябы даже и на Си?

watchcat382
()
Ответ на: комментарий от watchcat382

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

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

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от mister_VA

граница фрактальна

далее на последних страницах тех обычных учебников общесредне

были всякие «приложения»

далее в обычной гор библе были ошмётки серии «библиотека школьника»

так как у «нас»(в гогоде) игровые компьютерные залы были с 87-89 гг то домашний спектру-совместимый появился в 91

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

qulinxao3 ★★
()
Ответ на: комментарий от alysnix

это будет не столь красиво выглядеть.

Согласен. Но более надежные вещи не всегда красивы. А отсутствие рекурсии в реализации это именно надежность.

Более интересен вопрос сильная ли будет потеря в быстродействии и/или потреблении памяти при реализации без рекурсии? И будет ли вообще.

watchcat382
()
Ответ на: комментарий от ugoday

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

Знание латыни помогает при изучении венгерского также, как знание Питона помогает при изучении Си++. Падежи, времена, структура предложения, деление слов на глаголы и существительные, предлоги: это всё в латыни и венгерском примерно одинаково.

А инженера, которого выучили программировать на APL, а через неделю он уже пишет на Rust, я с трудом представляю.

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

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

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

monk ★★★★★
()
Ответ на: комментарий от alysnix

композиция - это столь любимая дремучими функциональщиками рекурсия.

???

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

Какая между ними связь?

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

Именно. Цитирую ваше сообщение: «сама идея применения цепочки вызовов функций к результатам друг друга».

monk ★★★★★
()
Ответ на: комментарий от mister_VA

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

Любая программа на XSLT.

monk ★★★★★
()
Ответ на: комментарий от watchcat382

А отсутствие рекурсии в реализации это именно надежность.

Чем рекурсия менее надёжна, чем цикл?

monk ★★★★★
()
Ответ на: комментарий от monk

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

Jack of all trades, master of none.

jpegqs
()
Ответ на: комментарий от watchcat382

Более интересен вопрос сильная ли будет потеря в быстродействии и/или потреблении памяти при реализации без рекурсии? И будет ли вообще.

При правильной реализации не будет вообще. А вот насчёт надёжности не уверен: если в рекурсивном алгоритме данные автоматически освобождаются по завершении функции, то в нерекурсивном алгоритме надо не забыть вручную освободить память, самостоятельно принять решение о том, сколько памяти запросить под стек, следить за его переполнением. Если программист хоть что-то забыл, то на непредусмотренных данных рекурсивная программа в худшем случае напишет, что произошло переполнение стека (и его можно увеличить через ulimit даже не перекомпилируя программу), а в нерекурсивной будет неопределённое поведение или аварийный останов, требующий перекомпиляции для увеличения внутреннего стека.

monk ★★★★★
()
Ответ на: комментарий от jpegqs

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

Предлагаю 1С.

monk ★★★★★
()
Ответ на: комментарий от monk

Композиция = получение функции из нескольких функций это и есть рекурсия. потому что в общем случае это можно сделать только вложенными вызовами функции. запись a(b(c(d(x)))) - прям об этом вопиет.

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

то бишь из

a(b(c(d(x)))) 

делать

{
  auto d_ = d(x);
  auto c_ = c(d_);
  auto b_ = b(c_);
  return a(b_);
}

тут функции не вызывают друг друга. но тогда, когда пишете «аналог» композиции на С++ - так и пишите. в виде итерации.

не знаю как там у вас в функциональных языках, но очевидно, что «композировать» можно и рекурсивно, навроде a(b(c(b(a(x)))). такая конструкция будет вычислима, так же как и обычная рекурсия.

alysnix ★★★
()
Ответ на: комментарий от watchcat382

Как проиллюстрировать процесс компиляции и линковки на Питоне?

Реализовать компоновщик на Питоне.

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

vM ★★
()
Ответ на: комментарий от monk

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

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

то есть

auto lrs = get_resources();
fun(lrs);
free_resourses(lrs);

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

alysnix ★★★
()
Ответ на: комментарий от alysnix

Ничего страшного:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in a
  File "<stdin>", line 2, in a
  File "<stdin>", line 2, in a
  [Previous line repeated 996 more times]
RecursionError: maximum recursion depth exceeded
vM ★★
()
Ответ на: комментарий от vM

Ничего страшного:

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

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от MOPKOBKA

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

Сделай по-уму scanf/printf.

no-such-file ★★★★★
()
Ответ на: комментарий от watchcat382

где в работе программиста применение рекурсии именно необходимо по соображениям производительности/памяти?

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

А где кроме спортивно-олимпиадного программирования

Ты децил не отдупляешь, из-за природы рекурсии на Си/С++ ты например не дождёшься конца вычислений fib, по крайней мере я дропнул на второй минуте, в то время как fib2 вычисляется мгновенно:

long long fib(int x)
{
	if (x == 0)
		return 0;
	if (x == 1)
		return 1;

	return fib(x - 1) + fib(x - 2);
}

long long fib2(const int  x)
{
	if (x < 0) return -1;
	long long* fib_n = (long long*)malloc((sizeof(long long) * (x + 1)));
	fib_n[0] = 0;
	fib_n[1] = 1;
	for (size_t i = 2; i <= x; i++) {
		fib_n[i] = fib_n[i - 1] + fib_n[i - 2];
	}
	long long y = fib_n[x];
	free(fib_n);
	return y;
}

int main()
{
	printf("Fib N = %lld", fib(90));

}
Ygor ★★★★★
()
Ответ на: комментарий от Ygor

из-за природы рекурсии на Си/С++…

в с/c++ у рекурсии вообще природы нет. тупо вызывается указанная функция на уровне железки. и как железка умеет вызывать функции и работать с памятью - такая скорость и будет.

alysnix ★★★
()
Ответ на: комментарий от alysnix

в с/c++ у рекурсии вообще природы нет

Эти два вызова fib(x - 1) + fib(x - 2) перевычисляются многократно для каждого узла рекурсивного дерева. И как бы там железка с памятью не работала это будет происходить. А чтобы не вычислять по 100500 раз одно и тоже и придумали динамическое программирование в этих языках.

Ygor ★★★★★
()
Ответ на: комментарий от Ygor

Что за фигню я читаю? Зачем выделять память для массива, когда нужно лишь два последних элемента.

#include <stdlib.h>
#include <stdio.h>

static unsigned long long fib(int n) {
	unsigned long long a = n & 1, b = 1;
	if (n < 0) return -1;
	if (n >>= 1) do b += a += b; while (--n);
	return a;
}

int main(int argc, char **argv) {
	argc > 1 && printf("%llu\n", fib(atoi(argv[1])));
}
jpegqs
()
Последнее исправление: jpegqs (всего исправлений: 1)
Ответ на: комментарий от Ygor

Это не природа рекурсии, это другой алгоритм. Вот правильный рекурсивный:

long long fibup(int x, long long pred, long long predpred)
{
	if (x == 0) return pred + predpred;
	return fubup(x-1, pred + predpred, pred);
}

long long fib(int n) 
{
	if n < 1 return 0 else return fibup(n-1, 0, 1);
}
monk ★★★★★
()
Ответ на: комментарий от watchcat382

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

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

ugoday ★★★★★
()
Ответ на: комментарий от watchcat382

Вот именно что если безразлично на чем - то зачем на микропитоне если можно хотябы даже и на Си?

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

ugoday ★★★★★
()
Ответ на: комментарий от monk

Знание латыни помогает при изучении венгерского также, как знание Питона помогает при изучении Си++. Падежи, времена, структура предложения, деление слов на глаголы и существительные, предлоги: это всё в латыни и венгерском примерно одинаково.

Кажется, мы встретили ещё одного теоретика. Расскажите о своём опыте, сколько иностранных языков знаете, какие, как опыт с одного языка на другой переносился.

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

Есть такое.

ugoday ★★★★★
()
Ответ на: комментарий от monk

Вот правильный рекурсивный:

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

Ygor ★★★★★
()
Ответ на: комментарий от MOPKOBKA

Раскрой мысль, какая ошибка будет в printf?

printf("Good bye %s\n");

Какая ошибка будет? Как сделать «по уму» статическую проверку без хаков компилятора?

no-such-file ★★★★★
()
Последнее исправление: no-such-file (всего исправлений: 2)
Ответ на: комментарий от monk

С чего это?

А как работает стек? Ты считаешь что при (x == 0) ты напрямую возвращаешь ответ пользователю, игнорируя всю глубину стека?

Ygor ★★★★★
()
Ответ на: комментарий от mister_VA

Вот, кажется придумал хороший пример. Пусть мы хотим написть такую функцию, которая:

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

б) записывает в файл (в рамках примера, считаем это возвращаемым значением) текущее время.

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

(let [executor "/tmp/executor.sh"
            cmd "#!/usr/bin/env sh\n date > /tmp/hello-mister_VA.log"]
        (spit executor cmd)
        (shell "chmod 755" executor)
        (shell executor))

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

ugoday ★★★★★
()
Ответ на: комментарий от monk

Значение каких венгерских слов в названии книги вы угадали?

https://books.google.ru/books?id=uJYvAAAAIAAJ

Падежи, времена, структура предложения, деление слов на глаголы и существительные, предлоги: это всё в латыни и венгерском примерно одинаково.

Вы сторонник п.и.-е.-уральской гипотезы?

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

vM ★★
()
Ограничение на отправку комментариев: