Installation¶
Install on Windows:
winget install -e --id Diskuv.dk
or Apple/Silicon:
sudo curl -o /usr/local/bin/dk https://diskuv.com/a/dk-exe/2.4.202506160116-signed/dk-darwin_arm64
sudo chmod +x /usr/local/bin/dk
or Apple/Intel:
sudo curl -o /usr/local/bin/dk https://diskuv.com/a/dk-exe/2.4.202506160116-signed/dk-darwin_x86_64
sudo chmod +x /usr/local/bin/dk
or Linux with glibc and libstdc++ (Debian, Ubuntu, etc. but not Alpine):
sudo curl -o /usr/local/bin/dk https://diskuv.com/a/dk-exe/2.4.202506160116-signed/dk-linux_x86_64
sudo chmod +x /usr/local/bin/dk
[ -x /usr/bin/dnf ] && sudo dnf install -y libstdc++
Say: Make it so¶
Copy and paste in your Terminal (PowerShell on Windows) and wait for a minute until you see Make it so.
:
dk -g dune -U "Tr1Stdlib_V414Io.StdIo.print_endline {|Make it so.|}" Run
Run it again and it will be fairly quick:
dk -g dune -U "Tr1Stdlib_V414Io.StdIo.print_endline {|Make it so.|}" Run
Congratulations, you have run your first script!
Let's breakdown exactly what happened ...
The -g dune
was the build generator option. dk
is technically a meta-build system like CMake, where build files are generated for a specific build system. Within the broader OCaml ecosystem, "Dune" is the conventional build system that compiles OCaml source code into executables. With -g dune
, dk
will create build files for Dune. The "Dune" build tool will then be invoked automatically to compile your scripts.
The -U <expression>
introduces the unit expression: Tr1Stdlib_V414Io.StdIo.print_endline {|Make it so.|}
. Expressions are the basic OCaml language construct where we can call functions. If you are unfamiliar with expressions, the chapter OCaml Programming: Correct + Efficient + Beautiful: Expressions is a great introduction. The "unit" in "unit expression" is the type of the expression. The "unit" type corresponds closely to the "void" return type in Java, C# and C. We'll be returning to the expression shortly.
The Run
command line argument is the name of the tool to invoke. The Run
tool naturally runs whatever you said on the command line. There are other tools which we'll see in the next section.
Let's get back to the unit expression: Tr1Stdlib_V414Io.StdIo.print_endline {|Make it so.|}
. You may be asking why would we have an expression that returns "unit" ... that is, it doesn't return anything? The answer is that the expression produces useful results (in this example, we'll be printing to the console screen), even without returning a value.
Tr1Stdlib_V414Io.StdIo.print_endline {|Make it so.|}
is a function call expression [¹]. We had to add double-quotes around the function call so that your Unix shell, Windows PowerShell or Command Prompt knows that the whole Tr1Stdlib_V414Io.StdIo.print_endline {|Make it so.|}
is the command line argument to -U
.
Let's compare the OCaml function call expression to the equivalent function call statement in Java:
System.out.println ("Make it so.");
OCaml is unusual among other languages in that you don't use parentheses separate the function reference from the function argument. In OCaml, we separate each function arguments from the function reference using whitespace.
Let's start with the function arguments. The first and only argument to Tr1Stdlib_V414Io.StdIo.print_endline
was {|Make it so.|}
. The {|Make it so.|}
is a string. The unusual {|
begin and |}
end tokens tell OCaml to interpret the intervening characters Make it so.
as a "literal" string: that is, a string that has no escape characters. Normally we would use double-quotes like "Make it so."
which is interpreted as a regular string. However, because we already used double-quotes to support Unix shell / Windows PowerShell / Command Prompt, we use the literal string syntax instead.
Now let's move back to the function reference. The Java function reference System.out.println
has the same behavior as Tr1Stdlib_V414Io.StdIo.print_endline
does in dk
: It prints a string and ends it with a newline.
The first dot-separated term of the function reference Tr1Stdlib_V414Io.StdIo.print_endline
was Tr1Stdlib_V414Io
. That is called the library id. You can find a description of all the dk
libraries at dkcoder-libraries(7).
The next term is StdIo
, which is a module defined in the Tr1Stdlib_V414Io
library. A module, at least for our purposes in this section, is a namespace for functions. There can be many modules, and the modules may be nested with a dot separator (.
) just like Java packages.
The last term, the last term is print_endline
, which is the function we want to call. Unfortunately at this time the dk
documentation is not rendering a description of the function, but when it does it will be here.
Cross-compiling¶
Now copy and paste and wait for several minutes (the first time only!):
dk -g dune -S "
module Http = DkNet_Std.Http
module Uri = Tr1Uri_Std.Uri
let print_endline = Tr1Stdlib_V414Io.StdIo.print_endline
" -U "
print_endline @@
Lwt_main.run @@
Http.fetch_url ~max_sz:4096 @@
Uri.of_string {|https://jigsaw.w3.org/HTTP/h-content-md5.html|}
" -O ReleaseSmall Exe
What happened? You created standalone executables for Linux and Windows and Android, all with one command, and if you are on macOS you also created standalone macOS executables.
Go ahead and find the standalone executable for your machine, and then run it:
target/ZzZz_Zz.Adhoc-android_arm32v7a
target/ZzZz_Zz.Adhoc-android_arm64v8a
target/ZzZz_Zz.Adhoc-android_x86_64
target/ZzZz_Zz.Adhoc-darwin_arm64
target/ZzZz_Zz.Adhoc-darwin_x86_64
target/ZzZz_Zz.Adhoc-linux_x86
target/ZzZz_Zz.Adhoc-linux_x86_64
target/ZzZz_Zz.Adhoc-windows_x86_64.exe
target/ZzZz_Zz.Adhoc-windows_x86.exe
In this section we introduced a few more command line options and arguments.
The last argument Exe
is the tool. In the last section we had used the Run
tool, but in this section we used the Exe
tool because we wanted to generate executables for different operating systems.
The -O ReleaseSmall
option tells dk
that we want to optimize the generated executable for a small file size and to exclude most debug information.
The -S <structure>
option introduces the structure (aka. contents) of a module. Before we had mentioned to consider a "module" as just a namespace for functions. Certainly the module can have functions, but it can also have what are called "module aliases".
Let consider the first module alias: module Http = DkNet_Std.Http
. What that alias does is let us use Http
instead of the longer DkNet_Std.Http
for the remainder of the module (which includes the unit expression -U <expression>
).
But the normal use of a module is to define values, especially functions. In our example above the function print_endline
was defined using the module binding:
let print_endline = Tr1Stdlib_V414Io.StdIo.print_endline
Bindings are very similar to module aliases, except they operate on values (including functions) rather than modules. So print_endline
can be used instead of the fully-qualifed function reference Tr1Stdlib_V414Io.StdIo.print_endline
for the remainder of the module.
The only thing we haven't explained is what are all those @@
doing in the function calls? @@
is an operator that places the terms on the right hand side of the expression in parentheses.
So:
print_endline @@
Lwt_main.run @@
Http.fetch_url ~max_sz:4096 @@
Uri.of_string {|https://jigsaw.w3.org/HTTP/h-content-md5.html|}
is really:
print_endline (
Lwt_main.run (
Http.fetch_url ~max_sz:4096 (
Uri.of_string {|https://jigsaw.w3.org/HTTP/h-content-md5.html|})))
Using a script file¶
Let's save the last script to a file. Copy and paste the following (notice we use Run
rather than -O ReleaseSmall Exe
):
dk -g dune -S "
module Http = DkNet_Std.Http
module Uri = Tr1Uri_Std.Uri
let print_endline = Tr1Stdlib_V414Io.StdIo.print_endline
" -U "
print_endline @@
Lwt_main.run @@
Http.fetch_url ~max_sz:4096 @@
Uri.of_string {|https://jigsaw.w3.org/HTTP/h-content-md5.html|}
" Run
You will see that it prints the contents for you (scroll up a bit):
module Http = DkNet_Std.Http
module Uri = Tr1Uri_Std.Uri
let print_endline = Tr1Stdlib_V414Io.StdIo.print_endline
let () =
print_endline @@ Lwt_main.run
@@ Http.fetch_url ~max_sz:4096
@@ Uri.of_string {|https://jigsaw.w3.org/HTTP/h-content-md5.html|}
Put that into a file; let's name it myfirstscript.ml
.
Then run it with:
dk -g dune -s myfirstscript.ml Run
Congratulations, you saved and ran your first script.
In the last section we had described how the -S <structure>
option introduce the structure (contents) of a module. Here we use -s <structure-file>
option instead, which just reads the module from the file rather than using command line option as-is.
Next Steps¶
You can:
- start the extended walk-through -or-
- browse the documentation