Написать переводчик Haskell в городе Haskell



классика программирования-написать интерпретатор Scheme Лиспа/схемы сюсюкать/. Мощность полного языка может быть использована для создания интерпретатора для подмножества языка.



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






Вот предыстория.

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



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



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

595   15  

15 ответов:

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

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

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

удачи! Определение языковых уровней для 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]    

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

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

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

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

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

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

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

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

дополнение:

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

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

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

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

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

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

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

Baskell-это реализация обучения,http://hackage.haskell.org/package/baskell

вы можете начать с выбора только, скажем, системы типов для реализации. Это примерно так же сложно, как интерпретатор схемы,http://hackage.haskell.org/package/thih

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

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

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

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

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

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

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

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

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

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

    • [] (ноль)

    • применение функции (левый ассоциативный)

    • инфиксной : (минусы, правую ассоциативность)

    • скобочки

    • переменной имена

    • имена функций

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

-- 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 с проверкой типов очень сложен. Если вы начнете с написания интерпретатора для вышеизложенного, добавление проверки типа к нему должно быть менее сложным.

на С (yacc-подобный парсер в Haskell), который имеет парсер Haskell.

этой может быть хорошей идеей - сделать крошечную версию NetLogo в Haskell. здесь - это крохотный переводчик.

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

Uhc/Ehc-это серия компиляторов, включающих / отключающих различные функции Haskell. http://www.cs.uu.nl/wiki/Ehc/WebHome#What_is_UHC_And_EHC

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

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

сайт также содержит игрушечные версии языков программирования ML-style, Prolog-style и OO.

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

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

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

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

  • операторы с настраиваемым приоритетом, ассоциативностью и фиксированностью,
  • вложенные комментарии
  • правила разметки
  • синтаксис шаблона
  • do- блоки и результате обессахаривания в монадическом код

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

мое предложение-реализовать проверку типов и интерпретатор для Core вместо полного Haskell. Обе эти задачи уже достаточно сложны сами по себе. Этот язык, хотя и является строго типизированным функциональным языком, гораздо менее сложен в плане оптимизации и генерации кода. Однако он по-прежнему не зависит от базовой машины. Поэтому GHC использует его в качестве посредника язык и переводит на него большинство синтаксических конструкций Хаскелла.

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

вот несколько ссылок на документацию Core как используется в GHC:

Comments

    Ничего не найдено.