Какой самый простой способ создать компилятор F #, который работает на JVM и генерирует байт-код Java?

Текущий компилятор F # написан в F #, является открытым исходным кодом и работает на .Net и Mono, что позволяет выполнять его на многих платформах, включая Windows, Mac и Linux. F # Механизм кодовых предложений был использован для компиляции F # на JavaScript в таких проектах, как WebSharper, Pit и FunScript. Также представляется некоторый интерес к запуску кода F # на JVM.

Я считаю, что версия OCaml-компилятора использовалась первоначально Bootstrap компилятор F #.

Если кто-то хотел создать компилятор F #, который работает на JVM, было бы проще:

  • Измените существующий компилятор F #, чтобы исправить байт-код Java и затем скомпилировать компилятор F # с ним?
  • Использовать компилятор ML на основе JVM, например Yeti, чтобы загружать минимальный компилятор F # на JVM?
  • Повторно записать компилятор F # с нуля в Java, когда создается проект fjord?
  • Что-то еще?

Ответ 1

Другим вариантом, который, вероятно, следует рассмотреть, является преобразование байт-кода .NET CLR в байт-код JVM, например http://www.ikvm.net с JVM > CLR-байтами. Хотя этот подход был рассмотрен и отклонен владельцем фьорда.

Получение бай-ина сверху с опцией 1) и команда компилятора F # имеют подключаемые бэкэнды, которые могут испускать байт-код Java в теории, как будто это создаст наиболее полированное решение.

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

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

Ответ 2

Если бы мне действительно нужно было это сделать, я, вероятно, начинал бы с подхода №1 - добавляет JVM-сервер к существующему компилятору. Но я также попытался бы утверждать, что для другой целевой виртуальной машины.

Котировки не очень актуальны - как автор WebSharper я могу заверить вас, что, хотя цитаты могут дать вам хороший F # -подобный язык для программирования, они являются ограничительными и не оптимизированы. Я полагаю, что для потенциальных пользователей JVM F # бар будет намного выше - полная совместимость с языком и сопоставимая производительность. Это очень сложно.

Возьмите, например, хвостовые звонки. В WebSharper мы применяем эвристику для оптимизации некоторых локальных хвостовых вызовов для циклов в JavaScript, но этого недостаточно - вы вообще не можете полагаться на TCO, как в обычных библиотеках F #. Это нормально для WebSharper, так как наши пользователи не ожидают полного F #, но не будет нормально для порта JVM F #. Я считаю, что большинство реализаций JVM не делают TCO, поэтому его нужно будет реализовать с некоторой косвенностью, введя производительность.

Подход к повторной компиляции байт-кода, упомянутый @mythz, звучит очень привлекательно, поскольку он позволяет больше, чем просто портировать F # - в идеале он позволяет переносить больше программного обеспечения .NET на JVM. Я немного поработал с анализом байт-кода .NET на внутреннем проекте WebSharper 3.0 - мы рассматриваем возможность компиляции байт-кода .NET вместо котировок F # на JavaScript. Но там есть огромные проблемы:

  • Много кода в BCL непрозрачно (native) - и вы не можете декомпилировать его

  • Модель дженериков довольно сложна. Я реализовал среду выполнения JavaScript, которая моделирует обобщенные методы класса и метода, создание экземпляров, генерацию типов и базовое отражение с некоторой точностью и разумной производительностью. Это было довольно сложно в динамическом JavaScript с закрытием и, по-видимому, довольно сложно сделать это на JVM, но, возможно, я просто не вижу простого решения.

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

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

Кроме того, подход байт-кода не устраняет вопрос о том, как реализовать хвостовые вызовы. AFAIK, Scala не реализует tailcalls. У них, безусловно, есть талант и финансирование для этого - тот факт, что они этого не делают, много говорит о том, насколько практично это делать TCO на JVM. Для нашего .NET- > JavaScript-порта я, вероятно, поеду по аналогичному маршруту - никаких гарантий TCO, если вы специально не попросите батут, который будет работать, но стоить вам на порядок (или два) по производительности.

Ответ 3

Существует проект, который компилирует OCaml в JVM, OCaml-Java: он довольно полный и, в частности, может скомпилировать компилятор OCaml (написанный в OCaml). Я не уверен, какие аспекты языка F # вам интересны, но если вы в основном смотрите на создание зрелого строго типизированного функционального языка для JVM, это может быть хорошим вариантом.

Ответ 4

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

Ответ 5

Измените существующий компилятор F #, чтобы испустить байт-код Java, а затем скомпилировать компилятор F # с ним? Использовать компилятор ML на основе JVM, например Yeti, для Bootstrap - минимальный компилятор F # на JVM?

Портирование компилятора не должно быть таким жестким, если оно записано в F #.

Я бы, наверное, пошел первым путем, потому что это единственный способ, которым можно было бы скомпрометировать новый компилятор с компилятором .net F #.

Повторно записать компилятор F # с нуля в Java, как кажется, пытается создать проект фьорда?

Это, безусловно, наименее элегантный подход, ИМХО.

Что-то еще?

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

Например, не зная много F #, но я предполагаю, что легко использовать любые библиотеки .NET там. Это означает, что основная проблема заключается в том, чтобы каким-то образом переносить экосистему .NET.

Ответ 6

Я искал что-то в похожих строках, хотя это больше похоже на переводчик/компилятор F # на Akka. Что касается F # → JVM, я натолкнулся на два не вполне готовых варианта:

  1. F# -> [Fjord][1] -> JVM.

  2. F# -> [Funscript][2] -> [Vert.X][3] -> JVM