📜 ⬆️ ⬇️

Interpreter for HQ9 + on F #

While the full-scale article about supporting F # of various paradigms is still being prepared for release, I will try to take your attention with some pleasant and not burdening trivia.
Tell me, do you know that there is such a wonderful programming language in the world, like HQ9 +? And why is he so wonderful? Well, for example, name at least one other language where the legendary program “Hello, world!” Consists of one character. Notice, not the strings, not the operator, but the character - “H”. Moreover, this language is so good that Quine is written for it also with one character - “Q”.

But that's not all. The third is almost a classic task for a beginner (and not so) programmer - the conclusion of a famous (and very long) poem about 99 bottles ... yes, it is also carried out by one symbol - "9". Finally, the “+” symbol increases the battery set in the language, which unfortunately cannot be used at all - the vicissitudes of fate.
A full description of the language can be found on the website of its author .
Thus, the H + Q + QH program will produce the following result:
Hello, world!
H + Q + QH
H + Q + QH
Hello, world!
And the variable will be equal to 2.
Great language, isn't it? But do not worry, I will not teach you to program on it. Instead, I will just offer my version of the interpreter of this exciting esoteric language in F #. The algorithm does not shine with a special theoretical novelty, but allows one more time to evaluate the power of pattern matching, which is used here a little less than everywhere else. See for yourself:
#light
open System
let input = Console .ReadLine()
let mutable inc = 0

let bottles k =
match k with
|0 -> "no more bottles"
|1 -> "1 bottle"
|_ -> k.ToString() + " bottles"

let rec poem k =
match k with
|0 -> printfn "No more bottles of beer on the wall, no more bottles of beer.\r\nGo to the store and buy some more, 99 bottles of beer on the wall."
|_ -> printfn "%s of beer on the wall, %s of beer.\r\nTake one down and pass it around, %s of beer on the wall." (bottles k) (bottles k) (bottles (k-1))
poem (k-1)

let parse ch =
match ch with
| 'H' | 'h' -> printfn "Hello, world!"
| 'Q' | 'q' -> printfn "%s" input
| '+' -> inc <- inc+1
| '9' -> poem 99
|_ -> ()

input |> Seq.iter parse
printfn "Debug information: Accumulator = %d" inc
let wait = Console .ReadKey()




We will read the HQ9 + program from the console, for which we include the System library (instead of using the sisharopvosky using open here).
The first two functions serve for the most complicated operation itself - the output of a poem about bottles. The first one determines the correct form of endings depending on the number of bottles left, the second one gives the complete correct couplet and, as we are used to, is sent to recursion.
The third function is the main one and performs some actions on the symbol issued to it. As we remember, the string itself is a sequence of characters, so in order to parse individual characters, we simply apply the Seq.iter method to it with a specific function as a parameter.
By the way, I think someone who has not previously encountered functional programming may have a reasonable question, how Seq.iter differs from Seq.map (as well as List.iter and Arr.iter from the corresponding map). At first glance, both of them apply a certain function to all elements of a sequence. But there are differences, and very critical ones. To understand this, just look at the signature:

val iter: ('a -> unit) -> seq<'a> -> unit
val map: ('a -> 'b) -> seq<'a> -> seq<'b>


')
The unit type in F # is the same as void in C #. Thus, Map translates one sequence into another, in accordance with some conversion function, Iter also applies a certain function to the elements of the sequence, the meaning of which is in the side effect, which of course violates the dogma of the OP, but allows you to simply perform some routine operations, such as output.
Another violation of the OP, which is more fully, as promised, the next time is the keyword mutable when defining the function “variable” inc. Now we can redefine it during program execution using the <- symbol.
Here is such a simple programming language HQ9 +, and at least a simple interpreter for it.
Well, if we are talking about quineas, then we need to bring quine to F # itself. It is unfortunately not as short as on HQ9 +.
#light
open System
let s = "#light
open System
let s = {0}{1}{0}
Console.Write(s,{0},s)"

Console .Write(s, '"' ,s)



I think that even by eye it is clear that the program really issues its code.
Perhaps, it’s not very pleasant in this Quine that it uses framework Console.Write instead of native printf, but in this case they are really more convenient, and the presence of .Net should give us advantages over the same OCaml. Here we will use them.
That seems to be all for today.

Source: https://habr.com/ru/post/53988/


All Articles