{"id":28955826,"url":"https://github.com/albertprz/polyglot","last_synced_at":"2025-06-23T20:10:14.913Z","repository":{"id":137411504,"uuid":"471680275","full_name":"albertprz/polyglot","owner":"albertprz","description":"Haskell to Purescript \u0026 Scala 3 transpiler","archived":false,"fork":false,"pushed_at":"2023-11-23T20:49:04.000Z","size":447,"stargazers_count":6,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-13T01:43:59.383Z","etag":null,"topics":["compiler-design","parser","transpiler"],"latest_commit_sha":null,"homepage":"https://hackage.haskell.org/package/polyglot","language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/albertprz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2022-03-19T11:49:48.000Z","updated_at":"2024-06-23T00:46:23.000Z","dependencies_parsed_at":"2023-11-23T21:44:48.554Z","dependency_job_id":null,"html_url":"https://github.com/albertprz/polyglot","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/albertprz/polyglot","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/albertprz%2Fpolyglot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/albertprz%2Fpolyglot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/albertprz%2Fpolyglot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/albertprz%2Fpolyglot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/albertprz","download_url":"https://codeload.github.com/albertprz/polyglot/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/albertprz%2Fpolyglot/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261548741,"owners_count":23175499,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["compiler-design","parser","transpiler"],"created_at":"2025-06-23T20:10:14.267Z","updated_at":"2025-06-23T20:10:14.898Z","avatar_url":"https://github.com/albertprz.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# polyglot\n\n## Description\n\nCLI tool to transpile Haskell modules to several target languages.\n\nThe CLI can convert individual Haskell files as well as recursively\nconvert directory trees (or entire projects).\n\nThere are a few options available to, for example, \nwatch a file / directory and reactively convert it whenever modified,\nas well as to format the output target language files.\n\nAt the moment, only parsing of Haskell 98 / 2010 standards along with a subset of GHC Syntax Extensions is supported (for example, there is currently no support for either Template Haskell or some of the GHC Syntax Extensions, such as GADTs and Type Families).\n\n## Usage\n\n```\nUsage: polyglot (-l|--language ARG) (-i|--input ARG) (-o|--output ARG) \n                [-f|--format] [-w|--watch] [--clear]\n\n  Compile Haskell file(s) into a target language.\n\nAvailable options:\n  -h,--help                Show this help text\n  -l,--language ARG        Target language\n  -i,--input ARG           Path of input Haskell file or directory\n  -o,--output ARG          Path of output file or directory\n  -f,--format              Apply formatter on output file(s)\n  -w,--watch               Watch for changes and convert automatically\n  --clear                  Clear the output directory contents before conversion\n\nSupported languages: Purescript, Scala\n```\n\n## Details\n\nThis CLI tool aims to perform a one-to-one mapping between Haskell and target language constructs.\nThis can be done in most cases, because all of the available target languages support many of Haskell key features that are not necessarily available in other mainstream languages, such as Higher Kinded Types, Typeclasses, GADTs \u0026 Higher Rank Polymorphism.\n\nHowever, the conversion can be lossy, so some information can be lost in the process. At the same time, it can be necessary to provide some extra information in the target language version of the source file (most prominently (type / kind) signatures, due to less powerful type inference mechanisms than Hindley-Millner in the target language).\n\nThe resulting files will have a dependency on some kind of prelude library that will expose all of the usual functions, data types, type classes and instances included in the Haskell prelude.\n\nAlso, bear in mind that in some cases due to different call semantics (lazy or call-by-need vs strict) and also runtime support for features (such as tail call optimization), the resulting files in the target language will probably need on some cases to be manually adapted post conversion, to preserve or approximate to the original Haskell code runtime characteristics.\n\nIn any case, it can be helpful to check the output files and manually adapt them as desired, because many Haskell idioms may not be the best match in the target language (This can be specially the case for languages that are not in the ML family (such as Scala)). \n\n\n## Examples\n\n\nSample Haskell snippet:\n\n```haskell\n\ndata Language\n  = Purescript\n  | Scala\n  deriving (Bounded, Enum, Eq, Ord, Show)\n\nparserOption :: Bookhound.Parser a -\u003e Options.Applicative.Mod Options.Applicative.OptionFields a -\u003e Parser a\nparserOption parser = option $ eitherReader $ reader\n  where\n    reader = mapLeft show . Bookhound.runParser parser . pack\n\n```\n\nConverted Purescript output (after formatting):\n\n```purescript\n\ndata Language\n  = Purescript\n  | Scala\nderive instance Bounded Language\nderive instance Enum Language\nderive instance Eq Language\nderive instance Ord Language\nderive instance Show Language\n\nparserOption :: forall a. Bookhound.Parser a -\u003e Options.Applicative.Mod Options.Applicative.OptionFields a -\u003e Parser a\nparserOption parser = option $ eitherReader $ reader\n  where\n    reader = mapLeft show \u003c\u003c\u003c Bookhound.runParser parser \u003c\u003c\u003c pack\n\n```\n\nSample Haskell snippet:\n\n```haskell\n\naction :: (ParseError -\u003e IO ()) -\u003e Opts -\u003e IO ()\naction errorAction Opts{language, sourcePath, targetPath, autoFormat} =\n  readFileUtf8 sourcePath\n  \u003e\u003e= (pack \u003c\u003c$\u003e\u003e) . traverse format . toTargetLanguage language\n  \u003e\u003e= either errorAction createDirAndWriteFile\n\n  where\n    createDirAndWriteFile x = createDirectoryIfMissing True finalDir *\u003e\n                              writeFileUtf8 finalPath x\n    finalDir                = takeDirectory finalPath\n    finalPath               = pathToLanguage language targetPath'\n\n    targetPath' = if isDir targetPath then\n                    replaceFileName targetPath (takeFileName sourcePath)\n                  else\n                    targetPath\n\n    format      = if autoFormat then\n                    readProcess (formatterExec language)\n                                [\"--stdin\", finalPath]\n                  else\n                    pure\n\n```\n\nConverted Scala output (after formatting):\n\n```scala\n\ndef action(x: ParseError =\u003e IO[Unit])(y: Opts): IO[Unit] =\n  (x, y) match\n    case (errorAction, Opts(language, sourcePath, targetPath, autoFormat)) =\u003e\n      def createDirAndWriteFile =\n        createDirectoryIfMissing(true)(finalDir) *\u003e writeFileUtf8(finalPath)(x)\n      def finalDir =\n        takeDirectory(finalPath)\n      def finalPath =\n        pathToLanguage(language, targetPath$)\n      def targetPath$ =\n        if isDir(targetPath) then\n          replaceFileName(targetPath)(takeFileName(sourcePath))\n        else targetPath\n      def format =\n        if autoFormat then\n          readProcess(formatterExec(language))(List(\"--stdin\", finalPath))\n        else pure\n\n      readFileUtf8(sourcePath)\n      \u003e\u003e= (pack \u003c\u003c\u0026\u003e\u003e _) ^ traverse(format) ^ toTargetLanguage(language)\n      \u003e\u003e= either(errorAction)(createDirAndWriteFile)\n\n```\n\n\n## Supported GHC Syntax Extensions\n\n``` yaml\n\n# Syntax Sugar\n- LambdaCase\n- MultiWayIf\n- PostfixOperators\n\n# Types\n- RankNTypes\n- ExplicitForAll\n- ScopedTypeVariables\n\n# Records\n- DuplicateRecordFields\n- NoFieldSelectors\n- NamedFieldPuns\n- RecordWildCards\n- OverloadedRecordDot\n\n# Type Classes\n- ConstrainedClassMethods\n- MultiParamTypeClasses\n\n# Deriving \n- StandaloneDeriving\n- DerivingVia\n- NewTypeDeriving\n- AnyClassDeriving\n- DerivingStrategies\n\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falbertprz%2Fpolyglot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falbertprz%2Fpolyglot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falbertprz%2Fpolyglot/lists"}