Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ A [feature-rich](https://livecodes.io/docs/features/), open-source, **client-sid
[![LiveCodes: npm version](https://img.shields.io/npm/v/livecodes)](https://www.npmjs.com/package/livecodes)
[![LiveCodes: npm downloads](https://img.shields.io/npm/dm/livecodes)](https://www.npmjs.com/package/livecodes)
[![LiveCodes: jsdelivr downloads](https://data.jsdelivr.com/v1/package/npm/livecodes/badge?style=rounded)](https://www.jsdelivr.com/package/npm/livecodes)
[![LiveCodes: languages](https://img.shields.io/badge/languages-102-blue)](https://livecodes.io/docs/languages/)
[![LiveCodes: languages](https://img.shields.io/badge/languages-103-blue)](https://livecodes.io/docs/languages/)
[![LiveCodes: docs](https://img.shields.io/badge/Documentation-575757?logo=gitbook&logoColor=white)](https://livecodes.io/docs/)
[![LiveCodes: llms.txt](https://img.shields.io/badge/llms.txt-575757?logo=googledocs&logoColor=white)](https://livecodes.io/docs/llms.txt)
[![LiveCodes: llms-full.txt](https://img.shields.io/badge/llms--full.txt-575757?logo=googledocs&logoColor=white)](https://livecodes.io/docs/llms-full.txt)
Expand Down
95 changes: 95 additions & 0 deletions docs/docs/languages/haskell.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Haskell

[Haskell](https://www.haskell.org/) is a statically typed, purely functional language with lazy evaluation.
LiveCodes uses [GHC in the browser](https://github.com/haskell-wasm/ghc-in-browser) to compile and run Haskell entirely client-side using WebAssembly.

## Usage

Write a Haskell module with a `main :: IO ()` entry point in the script editor:

```haskell
fibs :: [Integer]
fibs = 0 : 1 : zipWith (+) fibs (drop 1 fibs)

main :: IO ()
main = do
putStrLn "Hello, Haskell!"
print (take 10 fibs)
```

Output and compiler diagnostics appear in the console. The compiler runs in a web worker to keep the page responsive.

import LiveCodes from '../../src/components/LiveCodes.tsx';

<LiveCodes template="haskell" height="80vh" />

### Communication with JavaScript

JavaScript in the markup editor can access `livecodes.haskell`:

- `loaded`: a promise that resolves after the initial execution completes, or rejects if loading or execution fails. Compiler warnings do not reject it.
- `output`: the latest standard output as a string.
- `error`: the latest compiler/runtime diagnostics as a string (empty when there are none).
- `exitCode`: the exit code from the latest run (`0` for success).
- `run()`: runs the current Haskell source again and returns a promise resolving to `{ output, error, exitCode }`. Calls are queued, because GHC's interactive session cannot execute concurrently.

For example, display the initial output in the page:

```html
<pre id="output"></pre>
<script>
addEventListener('load', async () => {
try {
await livecodes.haskell.loaded;
document.querySelector('#output').textContent = livecodes.haskell.output;
} catch (error) {
document.querySelector('#output').textContent = livecodes.haskell.error;
}
});
</script>
```

### Limitations

- The first run downloads approximately 49 MB of compressed compiler and library data, plus the WebAssembly archive extractor. Initialization can take some time.
- This integration uses GHC 9.14.0.20251031 and the libraries bundled with that build. Installing Cabal/Hackage packages is not supported.
- Haskell runs in a worker, without direct access to the DOM or the page's JavaScript variables.
- Interactive standard input is not supported (stdin is empty).
- Output is line-buffered. Compiler diagnostics and program stderr share the `error` field, including warnings.
- Initialization has a five-minute timeout; each compilation/execution has a two-minute timeout. A timeout discards the worker, and a later run starts a new one.

## Language Info

### Name

`haskell`

### Alias

`hs`

### Extension

`.hs`

### Editor

`script`

### Compiler

[GHC in the browser](https://github.com/haskell-wasm/ghc-in-browser)

### Code Formatting

Not currently supported.

### Starter Template

https://livecodes.io/?template=haskell

### Links

- [Haskell](https://www.haskell.org/)
- [GHC documentation](https://www.haskell.org/ghc/documentation.html)
- [GHC in the browser](https://github.com/haskell-wasm/ghc-in-browser)
1 change: 1 addition & 0 deletions docs/src/components/LanguageSliders.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ export default function Sliders() {
{ name: 'cpp', title: 'C++' },
{ name: 'cpp-wasm', title: 'C++ (Wasm)' },
{ name: 'rust-wasm', title: 'Rust (Wasm)' },
{ name: 'haskell', title: 'Haskell' },
{ name: 'zig-wasm', title: 'Zig (Wasm)' },
{ name: 'java', title: 'Java' },
{ name: 'csharp-wasm', title: 'C# (Wasm)' },
Expand Down
1 change: 1 addition & 0 deletions docs/src/components/TemplateList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ const templates = [
{ name: 'cpp', title: 'C++ Starter', thumbnail: 'cpp.svg' },
{ name: 'cpp-wasm', title: 'C++ (Wasm) Starter', thumbnail: 'cpp.svg' },
{ name: 'rust-wasm', title: 'Rust (Wasm) Starter', thumbnail: 'rust.svg' },
{ name: 'haskell', title: 'Haskell Starter', thumbnail: 'haskell.svg' },
{ name: 'zig-wasm', title: 'Zig (Wasm) Starter', thumbnail: 'zig.svg' },
{ name: 'java', title: 'Java Starter', thumbnail: 'java.svg' },
{ name: 'csharp-wasm', title: 'C# (Wasm)', thumbnail: 'csharp.svg' },
Expand Down
20 changes: 20 additions & 0 deletions e2e/specs/starter.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,26 @@ test.describe('Starter Templates from UI', () => {
await expect(getResult().locator('text=You clicked')).toHaveText('You clicked 3 times.');
});

test('haskell Starter', async ({ page, getTestUrl }) => {
test.setTimeout(480_000);
await page.goto(getTestUrl({ template: 'haskell' }));
const { getResult, waitForResultUpdate } = await getLoadedApp(page);
await waitForResultUpdate({ timeout: 420_000 });
await expect(getResult().locator('#output')).toHaveText(
'Hello, Haskell!\nThe first 10 Fibonacci numbers:\n[0,1,1,2,3,5,8,13,21,34]',
{ timeout: 420_000 },
);
const run = (code: string) =>
getResult().evaluate(async (source) => {
document.querySelector('script[type="text/haskell"]')!.textContent = source;
return (window as any).livecodes.haskell.run();
}, code);
const failure = await run('main = missingValue');
expect(failure.error).toContain('missingValue');
const recovered = await run('main = print (sum [1..10])');
expect(recovered).toEqual({ output: '55\n', error: '', exitCode: 0 });
});

test('d3 Starter', async ({ page, getTestUrl, editor }) => {
test.slow();

Expand Down
3 changes: 2 additions & 1 deletion functions/vendors/templates.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export const starterTemplates = {
"cpp": "C++ Starter",
"cpp-wasm": "C++ (Wasm) Starter",
"rust-wasm": "Rust (Wasm) Starter",
"haskell": "Haskell Starter",
"zig-wasm": "Zig (Wasm) Starter",
"java": "Java Starter",
"csharp-wasm": "C# (Wasm) Starter",
Expand All @@ -72,4 +73,4 @@ export const starterTemplates = {
"minizinc": "MiniZinc Starter",
"blockly": "Blockly Starter",
"diagrams": "Diagrams Starter"
}
}
2 changes: 2 additions & 0 deletions scripts/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,8 @@ const iifeBuild = () =>
'languages/fsharp/lang-fsharp-compiler.ts',
'languages/fsharp-wasm/lang-fsharp-wasm-script.ts',
'languages/haml/lang-haml-compiler.ts',
'languages/haskell/lang-haskell-script.ts',
'languages/haskell/lang-haskell-worker.ts',
'languages/handlebars/lang-handlebars-compiler.ts',
'languages/imba/lang-imba-compiler.ts',
'languages/jinja/lang-jinja-compiler.ts',
Expand Down
3 changes: 2 additions & 1 deletion server/php/inc/starter-templates.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"cpp": "C++ Starter",
"cpp-wasm": "C++ (Wasm) Starter",
"rust-wasm": "Rust (Wasm) Starter",
"haskell": "Haskell Starter",
"zig-wasm": "Zig (Wasm) Starter",
"java": "Java Starter",
"csharp-wasm": "C# (Wasm) Starter",
Expand All @@ -72,4 +73,4 @@
"minizinc": "MiniZinc Starter",
"blockly": "Blockly Starter",
"diagrams": "Diagrams Starter"
}
}
1 change: 1 addition & 0 deletions src/livecodes/UI/command-menu-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ export const getCommandMenuActions = ({
'cpp',
'cpp-wasm',
'rust-wasm',
'haskell',
'zig-wasm',
'java',
'csharp-wasm',
Expand Down
1 change: 1 addition & 0 deletions src/livecodes/assets/templates/haskell.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/livecodes/assets/wasm/bsdtar.wasm
Binary file not shown.
7 changes: 6 additions & 1 deletion src/livecodes/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4598,7 +4598,11 @@ const handleTestEditor = () => {
const handleResultLoading = () => {
eventsManager.addEventListener(window, 'message', (event: any) => {
const iframe = UI.getResultIFrameElement();
if (!iframe || event.source !== iframe.contentWindow) {
if (
!iframe ||
event.source !== iframe.contentWindow ||
event.origin !== sandboxService.getOrigin()
) {
return;
}
if (event.data.type === 'loading') {
Expand All @@ -4619,6 +4623,7 @@ const handleResultLoading = () => {
isEmbed ||
!iframe ||
event.source !== iframe.contentWindow ||
event.origin !== sandboxService.getOrigin() ||
event.data.type !== 'loading' ||
event.data.payload !== false ||
getConfig().mode !== 'result'
Expand Down
28 changes: 28 additions & 0 deletions src/livecodes/html/language-info.html
Original file line number Diff line number Diff line change
Expand Up @@ -1137,6 +1137,34 @@ <h3 data-i18n="language-info:nunjucks.name">Nunjucks</h3>
</li>
</ul>
</section>
<section data-lang="haskell">
<h3 data-i18n="language-info:haskell.name">Haskell</h3>
<div data-i18n="language-info:haskell.desc" data-i18n-prop="innerHTML">
<p>
Haskell is a statically typed, purely functional programming language with lazy evaluation.
</p>
<p>LiveCodes runs GHC in the browser using WebAssembly.</p>
</div>
<ul data-i18n="language-info:haskell.link" data-i18n-prop="innerHTML">
<li><a href="https://www.haskell.org/" target="_blank" rel="noopener">Haskell</a></li>
<li>
<a href="https://github.com/haskell-wasm/ghc-in-browser" target="_blank" rel="noopener"
>GHC in the browser</a
>
</li>
<li>
<a href="{{DOCS_BASE_URL}}languages/haskell" target="_blank" rel="noopener"
>Haskell in LiveCodes</a
>
</li>
<li>
<a href="?template=haskell" class="button" target="_parent" data-template="haskell"
>Starter Template</a
>
</li>
</ul>
</section>

<section data-lang="rust-wasm">
<h3 data-i18n="language-info:rustWasm.name">Rust (Wasm)</h3>
<div data-i18n="language-info:rustWasm.desc" data-i18n-prop="innerHTML">
Expand Down
9 changes: 9 additions & 0 deletions src/livecodes/i18n/locales/ar/language-info.lokalise.json
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,15 @@
"handlebars.name": {
"translation": "Handlebars"
},
"haskell.desc": {
"translation": "هاسكل هي لغة برمجة وظيفية خالصة ومُكتوبة بشكل ثابت، مع تقييم كسول. LiveCodes يشغّل GHC في المتصفح باستخدام WebAssembly."
},
"haskell.link": {
"translation": "<tag-1><tag-2>Haskell</tag-2></tag-1> <tag-3> <tag-4>GHC في المتصفح</tag-4> </tag-3> <tag-5> <tag-6>هاسكل في LiveCodes</tag-6> </tag-5> <tag-7> <tag-8>القالب الأولي</tag-8> </tag-7>"
},
"haskell.name": {
"translation": "Haskell"
},
"imba.desc": {
"translation": "اللغة الودودة للتطوير الشامل."
},
Expand Down
5 changes: 5 additions & 0 deletions src/livecodes/i18n/locales/ar/language-info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,11 @@ const languageInfo: I18nLangInfoTranslation = {
link: '<1><2>الموقع الرسمي</2></1> <3> <4>وثائق LiveCodes</4> </3>',
name: 'Handlebars',
},
haskell: {
desc: '<1>هاسكل هي لغة برمجة وظيفية خالصة ومُكتوبة بشكل ثابت، مع تقييم كسول.</1> <2>LiveCodes يشغّل GHC في المتصفح باستخدام WebAssembly.</2>',
link: '<1><2>Haskell</2></1> <3> <4>GHC في المتصفح</4> </3> <5> <6>هاسكل في LiveCodes</6> </5> <7> <8>القالب الأولي</8> </7>',
name: 'Haskell',
},
imba: {
desc: 'اللغة الودودة للتطوير الشامل.',
link: '<1><2>الموقع الرسمي</2></1>',
Expand Down
9 changes: 9 additions & 0 deletions src/livecodes/i18n/locales/ar/translation.lokalise.json
Original file line number Diff line number Diff line change
Expand Up @@ -1893,6 +1893,12 @@
"sync.syncStarted": {
"translation": "بدأت المزامنة..."
},
"templates.haskell.heading": {
"translation": "هاسكل في المتصفح"
},
"templates.haskell.loading": {
"translation": "جارٍ تحميل GHC..."
},
"templates.heading": {
"translation": "مشروع جديد"
},
Expand Down Expand Up @@ -1980,6 +1986,9 @@
"templates.starter.go-wasm": {
"translation": "قالب Go (Wasm)"
},
"templates.starter.haskell": {
"translation": "قالب Haskell"
},
"templates.starter.heading": {
"translation": "قوالب البداية"
},
Expand Down
5 changes: 5 additions & 0 deletions src/livecodes/i18n/locales/ar/translation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -965,6 +965,10 @@ const translation: I18nTranslation = {
syncStarted: 'بدأت المزامنة...',
},
templates: {
haskell: {
heading: 'هاسكل في المتصفح',
loading: 'جارٍ تحميل GHC...',
},
heading: 'مشروع جديد',
noUserTemplates: {
desc: 'يمكنك حفظ مشروع كقالب من <1></1>(قائمة التطبيق > حفظ باسم > قالب).',
Expand Down Expand Up @@ -999,6 +1003,7 @@ const translation: I18nTranslation = {
gleam: 'قالب Gleam',
go: 'قالب Go',
'go-wasm': 'قالب Go (Wasm)',
haskell: 'قالب Haskell',
heading: 'قوالب البداية',
imba: 'قالب Imba',
java: 'قالب Java',
Expand Down
9 changes: 9 additions & 0 deletions src/livecodes/i18n/locales/bn/language-info.lokalise.json
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,15 @@
"handlebars.name": {
"translation": "Handlebars"
},
"haskell.desc": {
"translation": "Haskell হল একটি স্ট্যাটিক্যালি টাইপড, সম্পূর্ণ ফাংশনাল প্রোগ্রামিং ভাষা, যেখানে lazy evaluation রয়েছে। LiveCodes WebAssembly ব্যবহার করে ব্রাউজারে GHC চালায়।"
},
"haskell.link": {
"translation": "<tag-1><tag-2>Haskell</tag-2></tag-1> <tag-3> <tag-4>ব্রাউজারে GHC</tag-4> </tag-3> <tag-5> <tag-6>LiveCodes-এ Haskell</tag-6> </tag-5> <tag-7> <tag-8>স্টার্টার টেমপ্লেট</tag-8> </tag-7>"
},
"haskell.name": {
"translation": "Haskell"
},
"imba.desc": {
"translation": "বন্ধুত্বপূর্ণ ফুল-স্ট্যাক ভাষা।"
},
Expand Down
5 changes: 5 additions & 0 deletions src/livecodes/i18n/locales/bn/language-info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,11 @@ const languageInfo: I18nLangInfoTranslation = {
link: '<1><2>অফিসিয়াল ওয়েবসাইট</2></1> <3> <4>LiveCodes ডকুমেন্টেশন</4> </3>',
name: 'Handlebars',
},
haskell: {
desc: '<1>Haskell হল একটি স্ট্যাটিক্যালি টাইপড, সম্পূর্ণ ফাংশনাল প্রোগ্রামিং ভাষা, যেখানে lazy evaluation রয়েছে।</1> <2>LiveCodes WebAssembly ব্যবহার করে ব্রাউজারে GHC চালায়।</2>',
link: '<1><2>Haskell</2></1> <3> <4>ব্রাউজারে GHC</4> </3> <5> <6>LiveCodes-এ Haskell</6> </5> <7> <8>স্টার্টার টেমপ্লেট</8> </7>',
name: 'Haskell',
},
imba: {
desc: 'বন্ধুত্বপূর্ণ ফুল-স্ট্যাক ভাষা।',
link: '<1><2>অফিসিয়াল ওয়েবসাইট</2></1>',
Expand Down
9 changes: 9 additions & 0 deletions src/livecodes/i18n/locales/bn/translation.lokalise.json
Original file line number Diff line number Diff line change
Expand Up @@ -1893,6 +1893,12 @@
"sync.syncStarted": {
"translation": "সিঙ্ক শুরু হয়েছে..."
},
"templates.haskell.heading": {
"translation": "ব্রাউজারে Haskell"
},
"templates.haskell.loading": {
"translation": "GHC লোড হচ্ছে..."
},
"templates.heading": {
"translation": "নতুন প্রজেক্ট"
},
Expand Down Expand Up @@ -1980,6 +1986,9 @@
"templates.starter.go-wasm": {
"translation": "Go (Wasm) স্টার্টার"
},
"templates.starter.haskell": {
"translation": "Haskell স্টার্টার"
},
"templates.starter.heading": {
"translation": "স্টার্টার টেমপ্লেট"
},
Expand Down
5 changes: 5 additions & 0 deletions src/livecodes/i18n/locales/bn/translation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -965,6 +965,10 @@ const translation: I18nTranslation = {
syncStarted: 'সিঙ্ক শুরু হয়েছে...',
},
templates: {
haskell: {
heading: 'ব্রাউজারে Haskell',
loading: 'GHC লোড হচ্ছে...',
},
heading: 'নতুন প্রজেক্ট',
noUserTemplates: {
desc: 'আপনি <1></1>(অ্যাপ&nbsp;মেনু&nbsp;&gt;&nbsp;সংরক্ষণ&nbsp;করুন&nbsp;&gt; টেমপ্লেট) থেকে একটি প্রজেক্ট টেমপ্লেট হিসাবে সংরক্ষণ করতে পারেন।',
Expand Down Expand Up @@ -999,6 +1003,7 @@ const translation: I18nTranslation = {
gleam: 'Gleam স্টার্টার',
go: 'Go স্টার্টার',
'go-wasm': 'Go (Wasm) স্টার্টার',
haskell: 'Haskell স্টার্টার',
heading: 'স্টার্টার টেমপ্লেট',
imba: 'Imba স্টার্টার',
java: 'Java স্টার্টার',
Expand Down
Loading
Loading