Haku is a toy functional language with grammar, syntax and vocabulary inspired by Japanese.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Wim Vanderbauwhede fd2812561e
Merge pull request 'Add Fibonacci example' (#1) from raehik/haku:fibonacci into main
1 year ago
examples Add Fibonacci example 1 year ago
Haku.rakumod Mostly better docs and more examples; also some new features such as adjectival functions. 1 year ago
HakuAST.rakumod Updates from devel, except examples 1 year ago
HakuActions.rakumod nm 1 year ago
HakuPrelude.rakumod Updates from devel, except examples 1 year ago
HakuReader.rakumod Updates from devel, except examples 1 year ago
JapaneseNumberParser.rakumod Updates from devel, except examples 1 year ago
LICENSE Initial commit 2 years ago
README.md A few more clarifications 1 year ago
Raku.rakumod nm 1 year ago
Romaji.rakumod Updates from devel, except examples 1 year ago
Scheme.rakumod Brought Raku emitter in line with Scheme emitter, to be tested. 1 year ago
TODO.md Changes from devel, mostly better error messages and flags 1 year ago
Tategaki.rakumod Updates from devel, except examples 1 year ago
haku Mostly better docs and more examples; also some new features such as adjectival functions. 1 year ago
haku-docs.md A few more clarifications 1 year ago
haku.raku Mostly better docs and more examples; also some new features such as adjectival functions. 1 year ago



A toy functional programming language based on literary Japanese.

Is Haku for you?

  • Haku lets you write programs that look very much like written Japanese. So you need to be familiar with written Japanese to program in Haku. I have added translations and explanations to the documentation.
  • Haku is an experiment, not a practical programming language. Several of its features are rather contrary.
  • The implementation is incomplete and buggy, and error messages are poor.


To run Haku you'll need to install the Raku programming language. If you plan to use Raku (it is a wonderful language), I recommend you use the Rakubrew installation tool.

Running Haku

I am assuming you'll run Haku on command line, in the directory cloned from Git or where you unzipped the downloaded archive.

In that directory is a script haku. If you want to run haku outside this directory, you'll need to add the path to the environment variable RAKULIB.

Example programs are in the subdirectory examples (horizontal writing) and examples/tategaki (vertical writing).

Usage: haku <Haku program, written horizontally or vertically, utf-8 text file>
    [--tategaki, -t] : do not run the program but print it vertically.
    [--miseru, -m] : just print the Raku source code, don't execute.
    [--yomudake, -y] : just print the Haku source after reading, as a single line. Don't execute.
  • The tategaki options is a pretty-printer but the generated code is valid Haku: if you save the result in a text file, haku can read it in and run it.
  • The miseru option shows the Raku code generated by the compiler.
  • The yomudake option prints the string that the compiler uses as input, i.e. the program source converted to a single line.


$ ./haku examples/tategaki/iroha_tategaki.haku

This should print


The first time you run haku will take quite a long time (several minutes) because Raku needs to compile the modules to bytecode. After that, it should only take a few seconds.

Haku by example

Example 1: Iroha

Iroha is the name of a famous poem in which every kana occurs only once. The i,ro,ha sequence is used for ordered lists, so it is similar to a,b,c (or x,y,z in this case).

Consider the following Haku program:

註 例のはくのプログラム。


In Romaji (Japanese written using the Latin script) this reads:

Chuu Rei no Haku no PUROGURAMU.

Hon toha
RAMUDA ha aru EKSU de EKUSU Kakeru EKUSU desu,
KAZUtachi ha 88 to 7100 to 55 desu,
I:RO:HA:Kuu ha KAZUtachi desu,
SHINKAZU ha I to RO no Wa desu,
SHINKAZU wo Miseru,
KEKKA ha (741 wo RAMUDA suru) Tasu919,
(KEKKA to SHINKAZU no Wa) wo Miseru
no Koto desu.

In this documentation I use capitals to indicate words starting with kanji (nouns, verbs and adjectives), and all caps for words originally written in katakana.

And the translation is

Comment: an example Haku program

Main is (the following things):
LAMBDA is, with a given X, X * X;
NUMBERs is 88 and 7100 and 55;
I:RO:HA:Empty is NUMBERs;
NEWNUMBER is the Sum of I and RO; 
RESULT is (do LAMBDA with 741) + 919;
Show (the Sum of RESULT and NEWNUMBER)

which compiles to the following Scheme code:

(define (displayln str) (display str) (newline))(define (hon)

; 例のはくのプログラム    
(define (hon)
    (let* (
            (RAMUDA (lambda (EKUSU) (* EKUSU EKUSU )))
            (KAZUTACHI (list 88 7100 55))
            (I (car KAZUTACHI))
            (RO (cadr KAZUTACHI))
            (HA (caddr KAZUTACHI))
            (SHINKAZU (+ I RO ))
            (KEKKA (+ (RAMUDA 741) 919 ))
        (displayln SHINKAZU)
        (displayln (+ KEKKA SHINKAZU ))


Let's take it apart:

註 ... 。

is a comment (註 chuu means "note").

The main program (called 本, hon, here meaning "main") has a fixed begin and end string:


In Romaji this reads "Hon to wa ... no koto desu.", roughly "Main is the following thing(s): ...".

In Scheme I emit a function as body of Hon a let*-binding (i.e. binding is sequential):

(define (hon)
    (let* (

In the example we have an number of different types of assignments:


"RAMUDA wa aru EKSU de EKSU kakeru EKSU desu"

Katakana is for variables, kanji for functions and keywords, hiragana for keywords and verb endings (e.g. in 掛ける and 見せる).

This roughly reads as "as for RAMUDA, with a given X it is X times X", so RAMUDA binds to a lambda function. In Scheme this becomes:

(RAMUDA (lambda (EKUSU) (* EKUSU EKUSU )))

Next we have an assignment to a list of number constants:


"KAZUTachi wa 88 to 7100 to 55 desu,"

Numbers are written in kanji. The particle to ("and") is the list separator. You can use the pluralising suffix 達 tachi to show that a variable name is plural. In Scheme this becomes:

(KAZUTACHI (list 88 7100 55))

Next we have a bit of syntactic sugar borrowed from Haskell (cons):


"I:RO:HA:Kuu wa KAZUTachi de,"

kuu means "empty". This means that the list is deconstructed into elements I, RO, HA and and empty list. Scheme does not have this kind of pattern matching so each assignment is generated separately.

The next assignment,


"SHINKAZU wa I to RO no Wa de"

is simply

"SHINKAZU is the sum of I and RO"


Then we have a print statement:


"SHINKAZU wo Miseru"

"To show SHINKAZU"

In Scheme:

(displayln SHINKAZU)

Then follows another assignment:


"KEKKA wa (741 wo RAMUDA suru) Tasu 919"

"KEKKA is (RAMUDA of 741) plus 919

(KEKKA (+ (RAMUDA 741) 919 ))

And finally we show the result of an expression:


"(KEKKA to SHINKAZU no Wa) wo Miseru"

"To show the sum of KEKKA and SHINKAZU"

(displayln (+ KEKKA SHINKAZU ))

Example 2: Length of a list

This example shows the use of named functions, conditionals and recursion. I will use Haskell as pseudocode instead of Scheme.




In Romaji:

Nagasa toha KAZUtachi to KAISUU de
Moshi KAZUtachi ga Kuu ni Hitoshii nara
KAISUU desukedo,
(KAZUtachi no shippou) to (KAISUU Tasu Ichi) no Nagasa
no Koto desu.

Jou toha 
KAZUtachi de KAZUtachi to Zero no Nagasa 
no Koto desu.

Hon toha
KAZUtachi ha ichi .. yonjuuni
NAGASA ha KAZUtachi no Jou    
NAGASA wo Miseru
no Koto desu.


Longness is (the following thing):
With NUMBERs and Count,
If NUMBERS is equal to Empty, Count 
but if this is not so
Longness of (Tail of Numbers) and (Count + 1)

Length is (the following thing):
With NUMBERs, 
Longness of NUMBERS and 0

Main is (the following things):
NUMBERS is 1 .. 42;
LENGTH is Length of NUMBERS;

(長さ and 丈 both mean "length" but to avoid a naming conflict, I literally translate nagasa as "long-ness".)

Let's start with the main program:

"KAZUtachi ha ichi .. yonjuuni"

kazutachi = [1 .. 42]

We create a list kazutachi with the range operation 〜

"NAGASA ha KAZUtachi no Jou"

nagasa = jou kazutachi

We call the function jou on kazutachi and bind the result to nagasa

"NAGASA wo Miseru"

print nagasa

The function jou is quite simple:

"Jou toha KAZUtachi de KAZUtachi to Zero no Nagasa no Koto desu."

jou kazutachi = nagasa kazutachi 0

Finally nagasa

Nagasa toha KAZUtachi to KAISUU de
Moshi KAZUtachi ga Kuu ni Hitoshii nara
KAISUU desukedo,
(KAZUtachi no shippou) to (KAISUU Tasu Ichi) no Nagasa
no Koto desu.

In Haskell:

nagasa kazutachi kaisuu = 
    if kazutachi == [] 
        then kaisuu 
        else nagasa (tail kazutachi) (kaisuu+1)

Example 3: Summing a list

This example shows the use of comments, named functions, conditionals, let-bindings and recursion. I will again use Haskell for the equivalent code.

註 再帰関数の例の「加える」。


註 主プログラム。


In Romaji:

Chuu Saikikansuu no Rei no "Kuwaeru".

Kuwaeru toha
KAZUtachi to SAMU de
(KAZUtachi no Nagasa) ga zero ni hitoshii baaiha,
SAMU desukeredo,
soudenai baaiha,
kono NOKOKAZUtachi to SHINSAMU wo Kuwaeru ni
KAZU:NOKOKAZUtachi ga KAZUtachi、
no Koto desu.


Hon toha
KOTAE ha34 to 8to 0 wo Kuwaeru,
KOTAE wo Miseru
no Koto desu.


Comment: Example recursive function "Sum"

Sum is:
Given NUMBERs and SUM,
in case the length of NUMBERs is zero,
it is SUM but
in case this is not so,

Comment: Main program.

Main is:
ANSWER is Sum of [34 and 8] and 0;
to show the ANSWER    

Starting again with the main program:

"KOTAE ha [sanjuuyon to hachi] to zero wo Kuwaeru"

kotae = kuwaeru [34,8] 0

Then the function 加える (kuwaeru, "so sum")

Kuwaeru to ha
KAZUtachi to SAMU de
(KAZUtachi no Nagasa) ga zero ni hitoshii baai ha
SAMU desukeredo,
soudenai baai ha,
kono NOKOKAZUtachi to SHINSAMU wo Kuwaeru ni
no Koto desu.    

This function uses the 場合 variant of the if-then-else


It also has a let-expression:


In Haskell this becomes:

kuwaeru kazutachi samu =
    if length kazutachi == 0 
        then samu 
                kazu:nokokazutachi = kazutachi
                shinsamu = samu + kazu
                kuwaeru nokokazutachi shinsamu

Language guide

  • Haku is a simple, mostly-pure, implicitly typed, strict functional language.
  • Think Scheme with a sprinkling of Haskell.
  • TODO: At the moment, all type checking is deferred to Raku, the implementation language. So the currently Haku is not really strict and more dynamically typed.


  • As Haku does not rely on whitespace, spaces and newlines are not delimiters.
  • Bindings in a let and expressions and bindings in the main program must be delimited by 、or 。.
  • At some places (e.g. after delimiters), newlines are allowed to ease readability.


All comments must start with 註 (chuu, "note") or 注 (chuu, "comment", so you can write 注意, "warning") and end with a . A newline is allowed after a comment.

Program structure

  • A haku program source file can contain named function definitions and must contain a main program, called" 本 (pronounced hon and meaning "main").

  • The main program differs from the functions in that functions must be pure and therefore consist of a single expression, whereas the main program can be a sequence of expressions, similar to the do-sequence in a Haskell main program. The main program is defined as


There are a few variants to make it sound a bit more formal:

  • 本とは can also be 本真とは. 本真 honma means "truth".
  • の事です。(no koto desu, "is this thing") can also be と言う事です (to iu koto desu, "the said thing")。

A newline is allowed after 本とは and after all bindings and expressions.


  • variables: the first character must be katakana; further characters katakana or number kanji. The last character can be 達 (tachi), to indicate a plural.
  • function names: must start with a kanji. If they are nouns, further characters are also kanji; if they are verbs, further characters are hiragana verb endings. If they are adjectives, the final character must be い i or な na.


  • integer: written using number kanji. For zero, either 零 (rei, means zero), ゼロ (ZERO, also means zero) or ◯ (maru, also zero). Negative number prefix is マイナス (MAINASU, "minus"), optional positive number prefix is プラス (PURASU,"plus"). All kanji for large numbers (億, 兆, 京, etc) are supported, please read my article if you are not familiar with them.
  • rational: two integers separated by 点 (ten, "point")
  • string: quotes are「」or 『』
  • list: consist of identifiers or constants separated by と (to, "and"). To nest lists, wrap them in ....

Named function definitions

In Haku, named function definitions are statements. The structure is

<function-name> とは <argument-list> で <expression> の事です。

The same closing variants as for 本 are allowed; a newline is allowed after とは, で and the expression. The function name should be either a verb, noun or adjective (-i or -na).


或 <argument-list> で <expression>

aru means "a certain ..., a given ..., some ...",

Function application

There are a few forms of function application:

  • Verb form:

      <arg-list> を [ <arg-list> で ] <function>
      misoshiru wo SUPUUN de Taberu
      To eat miso soup with a spoon
  • Adjectival verb form (single argument only):

      <function> <arg>
      Aoi Shingo
      green traffic light
  • Noun form:

      <arg-list> の [ 、 <arg-list> での ] <function>
      Roku to Nana no Seki
      the product of six and seven
  • Adjective form:

      <funtion> <argument>
      Okutta MESSEEJI
      the sent message

The argument list can optionally be followed by の皆 (no minna, "all of"). This is used in particular when applying map or fold. Also, instead of で you can use のために or の為に (no tame ni, "in order to").

Partial application

The arg list can be followed by だけ or 丈 (dake, "only") to indicate partial application.

Map and Fold

Haku has built-in map and foldl:

  • foldl: 畳み込む (Tatamikomu, "to fold")

  • map: 写像する (Shazou suru, "to map")


A 'nominal function' is either a noun, variable, lambda expression, a verb nominalised with の (no) or こと (koto), or a -na adjective nominalised by dropping -na.


zero~yon wo (aru KAZU de KAZU Kakeru Ni Tasu Ichi) de Shazou suru

Map (with a given NUMBER, NUMBER times two plus one) to 0 .. 4

Function composition

We use 後, 'のち' (nochi, "and then"), to compose functions:


Note that


corresponds to

f2 . f1 

Currently, you have to bind them to a variable or wrap them in a lambda to apply them (TODO)

Let binding

There are two forms. The first is more like where-clause (expression at the start):

この <expression> に <variable> が <expression> 、... 。

A newline is allowed after この (kono, "this"), に and every bind expression.

The second is more like a conventional let (expression at the end):

●<variable>は <expression>、

A newline is allowed after every bind expression. The is not full-width so for vertical writing and are also supported.

Conditional expressions

Similar to other Japanese natural programming languages, we use 若し or もし (moshi, "if, supposing") as the keyword to introduce an if-then-else. The condition can be either なら, ならば or 〜たら (all of them have a meaning close to "would be the case"). The 'true' expression can optionally be followed by ですけれども (desukeredomo, a polite "but") or variants; the 'false' branch is introduced by そうでなければ or そうでないなら (soudenakereba or soudenainara, "if that would not be the case").

For example

もし <cond-expression> ならば <expression> そうでなければ <expression> 。

そうでなければ can also be written そうでない. A newline and/or comma is allowed after なら and before and after そうでなければ. Before そうでなければ, an optional ですけれど/ですけど/ですけれども or ですが is allowed.

Currently, there is another form of if-then-else expression supported, which uses 場合 (baai, "in case"):


The ですけれど is optional and can also be ですけど, ですけれども or ですが; a newline and/or comma is allowed after 場合は and before そうでない.


Haku provides a minimal set of arithmetic and logical operations and numerical comparisons. Built-in operators in Haku can have a different syntax from ordinary function calls. There is no operator precedence handling, so combined expressions need parentheses.


Verb form:

<expression> <verb> <expression>


<expression> と <expression> を <verb>

+: 足す (Tasu)
-: 引く (Hiku)
*: 掛ける (Kakeru)
/: 割る (Waru)

Noun form:

<expression> と <expression> の <noun>

+: 和 (Wa)
-: 差 (Sa)
*: 積 (Seki)
/: 除 (Jo)

Logical (TODO)

Boolean values:

True: 陽 (You)
False: 陰 (In)

(These are the kanji for yang and yin, so they do not really mean "true" and "false" but close connotations such as light and darkness, sun and moon, positive and negative.)


A and B: A も B も
A or B: A また[は] B 
not A: 不A 

A mo B mo means "both A and B", mata means "or"

I will likely also support the formal names:

XOR: 排他的論理和 (Haitateki Ronriwa, exclusive logical sum)
OR: 論理和 (Ronriwa, logical sum)
AND: 論理積 (Ronriseki, logical product)
NOT: 論理否定 (Ronrihitei, logical negation)


<expression> が <expression> <comparison-operation>

==: に等しい (ni hitoshii)
>: より多い (yori ooi)
<: より少ない (yori sukunai)


>=: 以上 (ijou)
<=: 以下 (ika)


  • Haku list are simply expressions separated by と to ( or に ni "at, into", から kara "from" or まで made "to"), without parentheses.

  • Square brackets (角括弧 kakugakko) are used for nesting lists.

  • The empty list is 空 (Kuu, "empty").

  • Lists have a minimal set of list manipulation functions:

      length: <list>の長さ (Nagasa)
      head: <list>の頭 (Atama)
      tail: <list>の尻尾 (Shippou)
      cons:・(中黒) (Nakamaru)
      concatenation: <list1>と<list2>を合わせる (Awaseru)
      range operator: <integer>〜<integer> 
      reverse: 逆な<list> (Gyaku na, an adjectival function)


  • Maps ("dictionaries") are created from lists of pairs,


    or from an empty list


    or shorter


図を作る Zu wo Tsukuru means "to create a map".

  • Maps support the following functions:

      has: <map>に<key>が有る (ga Aru)
      insert: <map>に<key>と<value>を入れる (wo Ireru)
      lookup: <map>に<key>を正引きする (TODO: 探索する) (Seibiki suru, Tansaku suru) 
      delete: <map>から<key>を消す
      length: <map>の長さ 
      keys:    <map>の鍵 (Kagi)
      values:  <map>の値 (Atai)

Interpolation in strings (TODO)

《バリュー》 returns a string.

System call (TODO)

機関で「<system call string>」する

機関 kikan means "system".

Any string will be passed on to the shell for execution.


  • The print function is called 見せる miseru, "to show", and returns the stringified argument.



  • Minimal file I/O for text files only.

          <file>を<mode>の為に開ける (_Akeru_)
          <mode>: 読む (Yomu, read) or 書く (Kaku, write)
          for read-write
      write: string>を<filehandle>で書く
          a single line: <filehandle>から一線を読む、(Issen, a single line)
          all lines: <filehandle>から全線を読む、(Zensen, all lines)
      close: <filehandle>を閉める (Shimeru)
      eof: <filehandle>の終了 (Shuuryou, TODO)



Modules and imports



Haku tries to be more like a natural language. Apart from adopting Japanese writing and word order, it does this mainly in two ways:

Verb conjugation on function calls

Haku lets you conjugate the verbs for a function call. For example:

  • Given a function send:


    and an argument message:

  • In Scheme:

      (send message)
  • Plain Haku

      MESSEEGI wo Okuru
      “To send a message”
  • Polite Haku

      MESSEEGI wo Okutte kudasai
      “Please send the message”
  • Insistent Haku

      MESSEEGI wo Okunasai
      “Do send the message”
  • Adjectival

      Okutta MESSEEGI
      “The sent message”

TODO: Not all of this works yet, currently you can do dictionary form (adjectival or plain), -te form with or without 下さい、しなさい and even くれて. And です can be で御座います (degozaimasu).

Choice of list separators and function application constructs

There is a lot of choice in how to express certain constructs, in particular function application. For example,

Shorui wo Yomu no tame no Akeru
"to open the document for reading"  
open doc ReadOnly

Jisho ni KAGI to BARYUU wo Ireru
"to insert a key and value in the dictionary"
insert dict key value

JISHO ni KAGI wo Seibiki suru
"to lookup a key in the dictionary"
lookup dict key

Jisho kara KAGI wo Kesu
"to delete a key from the dictionary"
delete dict key

KAGI to BARYUU kara Zu wo Tsukuru
"to create a map from key and value"
fromList [(key,value)]

KAZUtachi to AKU wo Tasu no de Tatamikomu
"to fold the numbers and the acc with addition"
foldl add acc xs

Kazutachi no minna wo nibai de Shazou suru
"to map all numbers with double"
map double xs

Roku ni Nana wo Tasu
"add seven to six"
Roku de Kakeru NANA
"multiply seven with six"
Rok to Nana no Seki
"the product of six and seven"

I plan to add support for adjectives as well (TODO).


The Wikipedia page on Non-English-based programming languages lists eight different languages based on Japanese. So why make a ninth one? The short answer is, to see what I would end up with. The slightly longer answer is that these other eight languages serve a practical purpose: they want to make programming easier for Japanese native speakers, and most of them target education.

My motivation to create Haku is very different. I don't want to create a practical language. I want to explore what the result is of creating a programming language based on a non-English language, in terms of syntax, grammar and vocabulary. In particular, I want to allow the programmer to control the register of the language to some extent (informal/polite/formal).


I also want the language to be closer, at lease visually, to literary Japanese. Therefore Haku does not use Roman letters, Arabic digits or common arithmetic, logical and comparison operators. And it supports top-to-bottom, right-to-left writing.


The main motivation for Haku is the difference in grammar between Japanese and most Indo-European languages. In particular, it has subject-object-verb order. This makes the familiar programming constructs quite different.

Some time ago I ran a poll about how coders perceive function calls, and 3/4 of respondents answered "imperative" (other options were infinitive, noun, -ing form).

In Japanese, the imperative (命令形 meireikei, "command form") is rarely used. Therefore in Haku you can't use this form. Instead, you can use the plain form, -masu form or -te form, including -te kudasai. Whether a function is perceived as a verb or a noun is up to you, and the difference is clear from the syntax. If it is a noun, you can turn it into a verb by adding suru, and if it is a verb, you can add the 'no' or 'koto' nominalisers. And you can conjugate the verb forms.

Naming and giving meaning

In principle, programming language does not need to be based on natural language at all. The notorious example is APL, which uses symbols for everything. Agda programmers also tends to use lots of mathematical symbols. It works because they are very familiar with those symbols. An interesting question is if an experienced programmer who does not know Japanese could understand a Haku program; or if not, what the minimal changes would be to make it understandable.

To allow to investigate that question, the Scheme and Raku emitters for Haku supports (limited) transliteration to Romaji. And there is also Roku, but more about that later ...


Japanese does not use spaces. So how do we tokenise a string of Japanese?

  • There are three writing systems: katakana (angular), hiragana (squigly) and kanji (complicated).
  • Katakan is used in a similar way as italics
  • Nouns, verb, adjectives and adverbs normally start with a kanji
  • Hiragana is used for verb/adjective/adverb endings and "particles", small words or suffixes that help identify the words in a sentence.
  • A verb/adjective/adverb can't end with a hiragana character that represents a particle.

So we have some simple tokenisation rules:

  • a sequence of katakana
  • a kanji followed by more kanji or hiragana that do not represent particles
  • hiragana that represent particles

Where that fails, we can introduce parentheses. In practice, only specific adverbs and adjectives are used in Haku. For example:


ラムダ: katakana word
は: particle
或: pre-noun adjective
エクス: katakana word
で: particle
エクス: katakana word
掛ける: verb
エクス: katakana word 
です: verb (copula)


Haku is implemented in Raku, a gradually-typed multi-paradigm language.
The parser uses Rakus Grammars. It is a recursive descent, longest token match parser. The parser populates an AST using Hakus Actions. The AST is an algebraic datatype implemented using Hakus Parameterized Roles. The emitter generates Raku code which is executed via dynamic module loading. Currently all type checking is delegated to Raku.

About the name

I call it 'haku' because I like the sound of it, and also because that word can be written in many ways and mean many things in Japanese. I was definitely thinking about Haku from Spirited Away. Also, I like the resemblance with Raku, the implementation language. I would write it 珀 (amber) or 魄 (soul, spirit).