A Quick Introduction to the OCaml Programming Language
What are expressions, values & other fundamental aspects in OCaml?
You guys who are reading this blog are maybe taught this language(OCaml) as a part of your University curriculum or just wanted to learn functional programming and started with OCaml. In either cases this blog will be beneficial.
This is only going to be a brief intro to OCaml, so we are not covering Data Types in this article. That will come in the next blog.
I'm trying to achieve an unconventional approach to begin the series of OCaml programming tutorials. While many tutorials typically dive into data types from the outset, I've chosen to start by discussing how OCaml is different from other languages. In this introductory phase, we'll explore fundamental aspects of the language that come into play when writing code or during compilation, such as its type inference, immutability, and expression-oriented nature.
Let's dive in!
Let's Begin
OCaml is an objective expression-oriented programming language written in C. OCaml(Objective Caml) is an open-source, general-purpose, statically typed, functional language which is actually an extension of the Caml language with support of Object oriented programming. Sounds a lot right? Don't worry if you don't understand all of terms said above. The only key-term that can be new to everyone is the term expression-oriented
. What does it signify? Let's learn that first.
What is an Expression-Oriented Language?
All functional languages are expression oriented. In an expression oriented language, - nearly every code construct is an expression and thus yields a value.
In non-expression oriented languages we have two types of code constructs - statements & expressions where expressions must return a value that can be used elsewhere in the code while, statements generally perform actions that do not return a value. But any statement that returns a value is already qualified to be an expression.
The best example of a non-expression oriented language is C. Examples can help understand better -
/* Statements */
int x = 10; // Assignment statement
if (x > 4) { // Conditional Statement
x = 4;
}
for (int i = 0; i < 5; i++) { // Loop constructs are also statements
printf("%d\n", i);
}
/* abs() is a standard library function in C that computes
the absolute value of an integer */
abs(-5); // function calls are also statements
/* Expressions */
int sum = x + y;
/* Here `x+y` is an expression that evaluates to a value
that is assigned to a variable `sum` */
int max = (x > y) ? x : y;
/* Ternary operator( ?: ) is form of a conditional statement
converted into an expression */
int result = abs(-5) + 5; // This is an initialization expression
In the above examples, int x = 10;
and int result = abs(-5) + 5;
are examples of both declaration statements & initialization expression.
Also, function calls are both expressions & statements because they are complete instructions that perform actions in the program but also return a value (if the return type of the function is not void
).
So basically -
Statement | Expression |
Statements can only be declared. | Expressions can be assigned or used as operands. |
Statements create side effects to be useful. | Expressions are values or execute to values. |
Statements are two-sided in case of execution (they may be executed or not depending on the situation). | Expressions are unique in meaning ( because they always evaluate to a value & values are unique). |
As in an expression oriented language every statement is an expression, every piece of code returns some value.
Strong Emphasis on Immutability
An immutable value is a value whose state cannot be modified after it is created.
Although OCaml is not a purely functional language like HASKELL(because OCaml provides loops to use where necessary which shouldn't be in a purely functional language), OCaml strongly follows functional programming paradigm which encourages immutable data structures and values. Expressions, by their nature, are immutable—they compute values without modifying state. Mutation of states are seen as side-effects.
However it's worth noting that printing some value to the screen is also regarded as a side-effect! 😑
The good thing about immutability is it ensures data consistency by preventing unintended changes, reducing bugs caused by side effects.
What exactly are Values in OCaml?
Values are immutable entities representing any data in OCaml.
Unlike variables in imperative languages (like - C, Java, Python), which can change their contents over time, values in functional languages remain constant once defined.
let x = 55;; (* declaring x as an integer value of 55 *)
x = 0;; (* Trying to assign 0 to x will not work.
This expression will actualy check structural equality
between the value of x and 0, which will evaluate to false.
The `=` operator checks structural equality and `==` checks physical equality.
We will cover these in upcoming articles *)
(* Then what will this expression below do? *)
let x = 10;;
(* Trying the below code will print 10 to the screen *)
print_int x;;
Let's try to understand what exactly happened when we redeclared x as 10. As I said before - "values are immutable". So, it isn't any mutable assignment. It seems so because of the so called 'Shadow Effect'.
For now just know that every let
binding binds a new value to a variable. Even if an old variable was declared before with the same name, the new one will shadow the former one with the same name. The old variable will still exist but remain inaccessible.
Type Inference
As shown in the previous examples, we declare variables in OCaml with the let
keyword, without explicitly specifying the type of the value. But this does NOT necessarily signify that OCaml is dynamically typed.
Many people consider that OCaml is weakly typed. Which is not true. Although implicitly typed, the compiler comes with built-in type checker that helps ensure type safety in your code; which is an essential component of OCaml's static type system. This explains that this language is a strongly typed language.
Type inference in OCaml is a compile-time process where the type checker determines bindings' types before execution.
let name = "Debajyati";; (* The OCaml compiler will automatically infer
the type of the variable `name` as string *)
The type checker infers types, making OCaml statically typed, though type annotations are supported.
let name:string = "Debajyati";; (* Type Annotations are also supported *)
Recursion
In functional programming, recursive functions are preferred over loops for most tasks. Recursive functions are more idiomatic in OCaml and can lead to more concise and readable code. Yes, it's true.
This section is for those who are already familiar with the concept of recursion. Recursion is nothing but a function calling itself from its definition. e.g. -
(* This is a recursive function *)
let rec factorial n = if n = 0 then 1 else n * factorial (n-1);;
(* Recursive functions are defined with the `rec` keyword after
the `let` keyword. *)
If you want to know more about functions & recursions in OCaml stay tuned for my upcoming articles. : )
Recursion in OCaml promotes concise code by encapsulating repetitive patterns. It perfectly aligns with functional programming principles, holding immutable data.
Tail Recursion
Recursion approach can cause problems if not handled efficiently. Most programming languages implement function calls with a stack. This is called the call stack.
The size of the stack is usually limited by the operating system. Call Stack contains one element for each function call that has been started but not yet completed.
In order to perform all necessary computations without reaching a Stack overflow, - like all other functional languages, OCaml has a solution called the Tail Recursion or ( a more fancy term — Tail-Call Optimization.
We will learn about this approach in detail in the upcoming blogs.
Conclusion
I hope this introductory article sparked some interest or added some value to your time! Let me know in the comments. We will be covering data types next and more to come in future.
Until then follow me and please share this blog with your friends. :)
Have a great day ahead & most importantly -
Happy Coding! 🧑🏻💻 👩🏻💻