Про образование. Проблема в том, что каждый конкретный программист biased к своим любимым языкам, к своим любимым парадигмам, и считает, что учить надо именно так, чтобы максимизировать вовлечённость ученика в этот конкретный язык и парадигмы. Ответственный учитель должен абсолютно на 100% осознавать то, что он biased. Более того, он должен на 100% осознавать, почему он biased именно так, как biased, а не по-другому. Почему именно Haskell, а не Oberon. Иногда ответ может не понравится, но его нужно осознавать, чтобы своими ложными представлениями не заразить ученика. Ну, конечно, если у учителя уже нет тёплого местечка для таких учеников, которых он готовит под себя. Но тогда учитель должен честно объявлять о своих целях.
Например, если Вы начинаете учить человека со Схемы или Хаскеля, или Java, или Python, то он гарантированно получит огромные проблемы в понимании того, как работает железо, и для него работа на микроконтроллерах (а тема модная) будет очень долго казаться магией. У нас в универе такой эксперимент ставят на учащимися, и результат плачевен (с моей профессиональной точки зрения: люди могут идти в банки и кодить там, но запрограммировать простейший процесс на микроконтроллере или оптимизировать цикл для них - неподъёмная задача).
По мне так нормальное обучение программированию должно идти не от языков и их возможностей, а от практических задач и средств их решения. Кнут в этом смысле идеален, как форма представления материала.
Мы ставим конкретную задачу, выбираем алгоритм решения, кодируем. При этом, нужно понимать, что для кодирования простых алгоритмов, и ассемблер может быть эффективным инструментом. Программистам обязательно нужно показывать, как именно работает машина.
Си - это не плохой язык программирования, это язык, абстрагирующий ассемблерные парадигмы программирования. И тем он хорош. Если бы я учил людей программированию с нуля, и если бы у меня была задача научить хорошего программиста, а не адепта своей Схемо-секты, я бы поступил так:
1. Изучение архитектуры машины и API операционки (занатия 3-4) и простейшие алгоритмы на ассемблере. Благо, есть QEMU, есть Dos-Box, можно запускать код.
2. Изучение более сложных алгоритмов: сортировка там, поиск в ширину, может быть (занятия 3-4). Программирование на Си со словами: вот смотрите, у нас в простых алгоритмах возникали циклы, ветвления, процедуры и подпрограммы. Смотрите, как это поднимается на уровень выше в удобном синтаксисе. Считайте, что после этого у человека сразу отпадают проблемы с кучей языков императивного семейства, потому что идиомы примерно одинаковы. Синтаксис не важен!
3. Дальше можно ветвиться (на ФП или на ООП, кому как нравится; благо JS позволяет писать в обоих стилях), поднимая степень сложности задач. Здесь бы я прошёл SICP уже на том языке, на котором нравится учителю. SICP прекрасен тем, что он учит кодировать различные алгоритмические структуры (может и HtDP учит, но я не читал).
Со словами: вот видите, как мы на Си уделяли кучу времени деталям управления памятью, бла-бла-бла, но это не всегда рационально. Если нужно разработать сложную систему, можно взять более мощный язык, с более мощными парадигмами, и писать гораздо более сложный код быстрее. При чём, парадигмы нужно объяснять с переводом на ассемблер, чтобы люди понимали, насколько так или иная конструкция дорогая и уместная. Чтобы, например, не было иллюзий, что ленивый map (без оптимизаций) быстрее, чем энергичный map через reverse (без оптимизаций).
Но таких курсов особо нет. Поэтому, по моему разумению, если человек вынужден сам учиться программировать, то надо взять книгу "Секреты программирования игр", которая закрывает пункты 1, 2 более или менее, а потом надо взять SICP и порешать её на любом языке, который захочется освоить.