Напишите переводчика Haskell в Haskell

Классическое программирование состоит в том, чтобы написать интерпретатор Lisp/Scheme в Lisp/Scheme. Полномочия полного языка можно использовать для создания интерпретатора для подмножества языка.

Есть ли подобное упражнение для Haskell? Я хотел бы реализовать подмножество Haskell, используя Haskell в качестве движка. Конечно, это можно сделать, но есть ли онлайн-ресурсы, доступные для просмотра?


Здесь предыстория.

Я изучаю идею использования Haskell в качестве языка для изучения некоторых концепций в курсе Discrete Structures, который я преподаю. В этом семестре я остановился на Miranda, меньшем языке, который вдохновил Haskell. Миранда делает около 90% того, что я хотел бы сделать, но Haskell делает около 2000%.:)

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

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

Ответ 1

Мне нравится ваша цель, но это большая работа. Несколько советов:

  • Я работал над GHC, и вам не нужна какая-либо часть источников. Hugs - гораздо более простая, более чистая реализация, но, к сожалению, она находится на C.

  • Это небольшая часть головоломки, но Марк Джонс написал красивую бумагу под названием Typing Haskell в Haskell, которая была бы замечательной отправной точкой для вашего интерфейса.

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

Ответ 2

Существует полный анализатор Haskell: http://hackage.haskell.org/package/haskell-src-exts

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

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

parseModule :: String -> ParseResult Module

Затем у вас есть AST для модуля:

Module SrcLoc ModuleName [ModulePragma] (Maybe WarningText) (Maybe [ExportSpec]) [ImportDecl] [Decl]    

Тип Decl обширен: http://hackage.haskell.org/packages/archive/haskell-src-exts/1.9.0/doc/html/Language-Haskell-Exts-Syntax.html#t%3ADecl

Все, что вам нужно сделать, это определить белый список - какие объявления, импорт, символы, синтаксис доступны, затем пройти АСТ и выбросить "синтаксическую ошибку" на все, что вы не хотите, чтобы они знали еще. Вы можете использовать значение SrcLoc, прикрепленное к каждому node в AST:

data SrcLoc = SrcLoc
     { srcFilename :: String
     , srcLine :: Int
     , srcColumn :: Int
     }

Нет необходимости переустанавливать Haskell. Если вы хотите предоставить более дружественные ошибки компиляции, просто проанализируйте код, отфильтруйте его, отправьте его компилятору и проанализируйте вывод компилятора. Если он "не может соответствовать ожидаемому типу a против выведенного a -> b", то вы знаете, что, вероятно, слишком мало аргументов для функции.

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

Ответ 3

Вы хотите построить свой интерпретатор с нуля? Начните с внедрения более простого функционального языка, такого как лямбда-исчисление или вариант lisp. Для последнего есть довольно приятный wikibook, называемый Напишите себе схему за 48 часов, давая крутое и прагматичное введение в методы синтаксического анализа и интерпретации.

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

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

Дополнение:

Обратите внимание, что в Haskell у вас есть полный доступ к API-интерфейсу интерпретаторов (по крайней мере, под GHC), включая парсеры, компиляторы и, конечно же, интерпретаторы.

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

Ответ 4

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

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

Это будет похоже на HLint (а также его противоположность):

HLint (ранее доктор Хаскелл) читает программы Haskell и предлагает изменения, которые, надеюсь, облегчат их чтение. HLint также позволяет легко отключать нежелательные предложения и добавлять свои собственные предложения.

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

Ответ 6

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

Я написал компилятор подмножества для компиляции Haskell для компиляции для задачи Code Golf. Он принимает код подмножества Haskell на входе и выдает код C на выходе. Мне жаль, что доступной читаемой версии нет; Я вручную вложил вложенные определения в процессе самокомпилирования.

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

  • ленивая оценка. Если интерпретатор находится в Haskell, вам может не понадобиться ничего делать.

  • Определения функций с аргументами и защитой с шаблоном. Только беспокоитесь о шаблонах переменной, cons, nil и _.

  • Синтаксис простого выражения:

    • Целочисленные литералы

    • Литералы символов

    • [] (nil)

    • Функциональное приложение (левое ассоциативное)

    • Infix : (cons, right associative)

    • Скобки

    • Переменные имена

    • Названия функций

Более конкретно, напишите интерпретатор, который может запустить это:

-- tail :: [a] -> [a]
tail (_:xs) = xs

-- append :: [a] -> [a] -> [a]
append []     ys = ys
append (x:xs) ys = x : append xs ys

-- zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith f (a:as) (b:bs) = f a b : zipWith f as bs
zipWith _ _      _      = []

-- showList :: (a -> String) -> [a] -> String
showList _    []     = '[' : ']' : []
showList show (x:xs) = '[' : append (show x) (showItems show xs)

-- showItems :: (a -> String) -> [a] -> String
showItems show []     = ']' : []
showItems show (x:xs) = ',' : append (show x) (showItems show xs)

-- fibs :: [Int]
fibs = 0 : 1 : zipWith add fibs (tail fibs)

-- main :: String
main = showList showInt (take 40 fibs)

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

Ответ 7

Серия компиляторов EHC, вероятно, лучше всего: она активно развивается и, похоже, именно то, что вы хотите - серия небольших компиляторов/интерпретаторов лямбда-исчислений, кульминацией которых является Haskell'98.

Но вы также можете посмотреть на различные языки, разработанные на языках Пирса и языках программирования, или интерпретатор Helium (искалеченный Haskell, предназначенный для студентов http://en.wikipedia.org/wiki/Helium_(Haskell)).

Ответ 8

Вы можете посмотреть Happy (yacc-подобный парсер в Haskell), который имеет анализатор Haskell.

Ответ 10

см., если helium будет лучше основываться, чем стандартный haskell.

Ответ 12

Andrej Bauer Язык программирования Zoo имеет небольшую реализацию чисто функционального языка программирования, несколько нахально названного "minihaskell", Это около 700 строк OCaml, поэтому очень легко усваивается.

На сайте также представлены версии игрушек типа ML, стиля Prolog и OO.

Ответ 13

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

GHC в любом случае написана в Haskell, так что технически это остается с вашим вопросом о интерпретаторе Haskell, написанном в Haskell.

Вероятно, было бы не слишком сложно сделать все, что статически связано, а затем распространять только ваши настроенные GHCi, чтобы ученики не могли загружать другие исходные модули Haskell. Что касается того, сколько работы потребуется, чтобы не допустить их загрузки других объектных файлов Haskell, я понятия не имею. Возможно, вы захотите также отключить FFI, если у вас есть куча читеров в ваших классах:)

Ответ 14

Мне сказали, что Idris имеет довольно компактный парсер, не уверен, действительно ли он подходит для изменения, но он написан в Haskell.