364 search results for "function"
-
Values and Functions
Discarding Values Using Pattern Matching
<!-- END Version Two --> Tuples behave differently from records; contained data is anonymous, and its position is used to access it. To discard the email value from the tuple of the contact fi
Introduction -
Values and Functions
Scopes and Environments
<!-- With respect to the environment, there are no means to: - List its contents - Clear its contents - Remove a definition - Reset it to an earlier state --> Top-level expressions are also statemen
Introduction -
Values and Functions
Inner Shadowing
<!-- A name-value pair in a local expression *shadows* a binding with the same name in the global environment. In other words, the local binding temporarily hides the global one, making it inaccessib
Introduction -
Values and Functions
Same-Level Shadowing
There are now two definitions of h in the environment. The first h is unchanged. When the second h is defined, the first one becomes unreachable. Another kind of shadowing takes place when t
Introduction -
Higher Order Functions
Mapping Options
Note that both sides of the match return the same thing: if we had a None we return None , if we have a Some we return a Some . This way, the structure is preserved. Mapping an optional valu
Introduction -
Higher Order Functions
Mapping Results
Both of these are useful in different situations, such as wanting to change the type of errors, or only perform operations once we have an Ok value. We can map the value in the Ok value constr
Introduction -
Higher Order Functions
Mapping Custom Data Types
Note that the structure of the tree is preserved, but every time we encounter a value , we update it with (fn value) . When working with our custom data types, such as the tree we used in the
Introduction -
Higher Order Functions
Let-ops
This has the advantage of making code a lot more readable, without changing the behavior we've come to expect from bind calls. Thankfully, OCaml lets us redefine a subset of operators called let-
Introduction -
Your First OCaml Program
Installing and Using Modules From a Package
efer to the Sexplib documentation for more information. Next, define a string containing a valid S-expression in bin/main.ml . Parse it into a S-expression with the Sexplib.Sexp.of_string function, and then convert it back into a string with Sexplib.Sexp.to_string and print it. To illustrate this, let's update our hello project to parse a string containing an S-expression and print
First Steps -
Your First OCaml Program
Using the Preprocessor to Generate Code
le, and edit it to look like this: Let's assume we'd like hello to display its output as if it was a list of strings in UTop: ["hello"; "using"; "an"; "opam"; "library"] . To do that, we need a function turning a string list into a string , adding brackets, spaces, and commas. Instead of defining it ourselves, let's generate it automatically with a package. We'll use ppx_deriving . Here is how t
First Steps -
A Tour of OCaml
Type Conversion and Type-Inference
ison to other languages. Arguably, this saves more time than we lose by being more explicit. In OCaml you need to explicitly convert the integer to a floating point number using the float_of_int function: In the first example, + is intended to be used with integers, so it can't be used with the 2.5 float. In the second example, +. is intended to be used with floats, so it can't be used with th
First Steps -
A Tour of OCaml
Pattern Matching, Cont'd
mes, just as let does. In the third pattern, x designates the data inside the double-wrapped option. Pattern matching isn't limited to lists. Any kind of data can be inspected using it, except functions. Patterns are expressions that are compared to an inspected value. It could be performed using if … then … else … , but pattern matching is more convenient. Here is an example using the opti
First Steps -
A Tour of OCaml
Records
Here, the pattern { age = x; _ } is typed with the most recently declared record type that has an age field of type int . The type int is inferred from the expression 13 <= x && x <= 19 . The function is_teenager will only work with the found record type, here person . When defining gerard , no type needs to be declared. The type checker will search for a record which has exactly three fiel
First Steps -
Configuring Your Editor
1) Hovering for Type Information
This is a great feature that let's you see type information of any OCaml variable or function. All you have to do is place your cursor over the code and it will be displayed in the tooltip. VSCode Hovering
Tooling -
Configuring Your Editor
Finer configuration
OCaml-eglot can be finely configured, the project README gives several configuration paths to adapt perfectly to your workflow. You will also find there an exhaustive presentation of the different functions offered by the mode.
Tooling -
Configuring Your Editor
Getting Type Information
OCaml-eglot README provides a comprehensive overview of all the functions available in this mode! Emacs Type information Opening an OCaml file should launch an ocaml-lsp server, and you can convince yourself that it's working by using, for example, the ocaml-eglot-ty
Tooling -
Sequences
Iterating Over Sequences
ers forever,” and you have to press Ctrl-C to interrupt the execution. The following code is the same infinite loop without any output: The OCaml Standard Library also contains a Seq.iter function, which has the same behavior as List.iter . Writing this:
Data Structures -
Sequences
Reading a File with Seq.Unfold
ition. Note : To make the code in the next section work, create a file named "README.md" and add dummy content. We use a file generated by the following command: Before doing so, let's define a function that reads a file's line from a provided channel, with the type signature needed by Seq.unfold . For the next example, we will demonstrate the versatility of Seq.unfold by using it to read a
Data Structures -
Sequences
Consumer Example: Seq.iter
In print_seq , Seq.iter takes the function print_int and applies it to each element as they are generated. If List.iter was used, the whole integer list would be needed before displaying them starts.
Data Structures -
Modules
Interfaces and Implementations
module implementation) The public declarations of a module (the module interface) For this, we must distinguish: By default, anything defined in a module is accessible from other modules. Values, functions, types, or submodules, everything is public. This can be restricted to avoid exposing definitions that are not relevant from the outside.
Module System -
Modules
Stateful Modules
and third calls return the same results, showing that the internal state was reset. A module may have an internal state. This is the case for the Random module from the standard library. The functions Random.get_state and Random.set_state provide read and write access to the internal state, which is nameless and has an abstract type.
Module System -
Modules
Conclusion
Functors, which act like functions from modules to modules Libraries, which are compiled modules bundled together Packages, which are installation and distribution units Going further, here are the other means to handle OCaml softwar
Module System -
Mutability and Imperative Control Flow
Mutable Record Fields
Remark : the left arrow symbol <- for mutating mutable record field values is not an operator function, like the assignment operator ( := ) is for refs . It is rather a construct of the language, it has no type. In contrast to references, there is no special syntax to dereference a mutable recor
Introduction -
Mutability and Imperative Control Flow
For Loop
Note: Here is how to do the same thing using an iterator function: for loops are convenient to iterate over and modify arrays: When you use the downto keyword (instead of the to keyword), the counter decreases on every iteration of the loop. The body of
Introduction -
Mutability and Imperative Control Flow
Recommendations for Mutable State and Side Effects
Functional and imperative programming styles are often used together. However, not all ways of combining them give good results. We show some patterns and anti-patterns relating to mutable states and
Introduction -
Mutability and Imperative Control Flow
Good: Memoization
und in the cache (it's a miss), and the result is computed, stored in the cache, and returned. However, instead of precomputing everything, memoization uses a cache that is populated when calling the function. Either, the provided arguments The memoization technique relies on the same idea as the previous section's example: lookup results from a table of previously computed values.
Introduction -
The Compiler Backend: Bytecode and Native code
The Untyped Lambda Form
ype information into a simpler intermediate lambda form . The lambda form discards higher-level constructs such as modules and objects and replaces them with simpler values such as records and function pointers. Pattern matches are also analyzed and compiled into highly optimized automata.
Runtime & Compiler -
The Compiler Backend: Bytecode and Native code
Generating Portable Bytecode
<div class="note"> There are around 140 instructions in total, but most are just minor variants of commonly encountered operations (e.g., function application at a specific arity). You can find full details online . The preceding bytecode has been simplified from the lambda form into a set of simple instructions that are executed seriall
Runtime & Compiler -
The Compiler Backend: Bytecode and Native code
Compiling and Linking Bytecode
le program. The order in which .cmo arguments are presented on the command line defines the order in which compilation units are initialized at runtime. Remember that OCaml has no single main function like C, so this link order is more important than in C programs. The individual objects in the library are linked as regular cmo files in the order specified when the library file was built. I
Runtime & Compiler -
The Compiler Backend: Bytecode and Native code
Embedding OCaml Bytecode in C
ile. Here's an example to show how it all fits together. This mode causes ocamlc to output an object file containing the bytecode for the OCaml part of the program, as well as a caml_startup function. All of the OCaml modules are linked into this object file as bytecode, just as they would be for an executable. A consequence of using the bytecode compiler is that the final link phase must
Runtime & Compiler -
The Compiler Backend: Bytecode and Native code
Compiling Fast Native Code
ks modules together into an executable, it uses the contents of the cmx files to perform cross-module inlining across compilation units. This can be a significant speedup for standard library functions that are frequently used outside of their module. A .o file containing native object code A .cmx file containing extra information for linking and cross-module optimization A .cmi compile
Runtime & Compiler -
The Compiler Backend: Bytecode and Native code
Benchmarking Polymorphic Comparison
ee that this polymorphic comparison is much heavier than the simple monomorphic integer comparison from earlier. Let's confirm this hypothesis again by writing a quick Core_bench test with both functions:
Runtime & Compiler -
The Compiler Backend: Bytecode and Native code
Debugging Native Code Binaries
assembly when the library is compiled in debug mode. These include the CFI stubs you will have noticed in the profiling output earlier ( .cfi_start_proc and .cfi_end_proc to delimit an OCaml function call, for example). The native code compiler builds executables that can be debugged using conventional system debuggers such as GNU gdb . You need to compile your libraries with the -g optio
Runtime & Compiler -
The Compiler Backend: Bytecode and Native code
Interactive Breakpoints with the GNU Debugger
e first call to take : Now we can run this interactively within gdb : Compile and run this with debugging symbols. You should see the following output: Let's write a mutually recursive function that selects alternating values from a list. This isn't tail-recursive, so our stack size will grow as we single-step through the execution: Let's see name mangling in action with some interacti
Runtime & Compiler -
The Compiler Backend: Bytecode and Native code
Gprof
gmon.out when the program is executed. This profile information can then be examined using gprof . gprof produces an execution profile of an OCaml program by recording a call graph of which functions call one another, and recording the time these calls take during the program execution.
Runtime & Compiler -
The Compiler Backend: Bytecode and Native code
Perf
home page . This trace broadly reflects the results of the benchmark itself. The mutable benchmark consists of the combination of the call to test_mutable and the caml_modify write barrier function in the runtime. This adds up to slightly over half the execution time of the application. When this completes, you can interactively explore the results: Run Perf on a compiled binary to reco
Runtime & Compiler -
Memory Representation of Values
Distinguishing Integers and Pointers at Runtime
. This representation means that integers are unboxed runtime values in OCaml so that they can be stored directly without having to allocate a wrapper block. They can be passed directly to other function calls in registers and are generally the cheapest and fastest values to use in OCaml. OCaml values don't all have to be boxed at runtime. Instead, values use a single tag bit per word to disting
Runtime & Compiler -
Memory Representation of Values
Integers, Characters, and Other Basic Types
it are very efficient to use, since integers are never allocated on the heap. They can be passed directly in registers and not appear on the stack if you don't have too many parameters to your functions. Modern architectures such as x86_64 have a lot of spare registers to further improve the efficiency of using unboxed integers. Many basic types are efficiently stored as unboxed integers at
Runtime & Compiler -
Memory Representation of Values
Tuples, Records, and Arrays
The Obj.repr function retrieves the runtime representation of any OCaml value. Obj.is_block checks the bottom bit to determine if the value is a block header or an unboxed integer. You can check the difference be
Runtime & Compiler -
Memory Representation of Values
Floating-Point Numbers and Arrays
hich are not optimized in the same way and have the normal tuple tag value (0). This tells us that float arrays have a tag value of 254. Now let's test some sample values using the Obj.tag function to check that the allocated block has the expected runtime tag, and also use Obj.double_field to retrieve a float from within the block: First, let's check that float arrays do in fact have
Runtime & Compiler -
Memory Representation of Values
Custom Heap Blocks
ted. This finalizer has nothing to do with ordinary OCaml finalizers (as created by Gc.finalize and explained in Understanding The Garbage Collector ). They are instead used to call C cleanup functions such as free . The first word of the data within the custom block is a C pointer to a struct of custom operations. The custom block cannot have pointers to OCaml blocks and is opaque to the
Runtime & Compiler -
Operators
Defining Binary Operators
It is a recommended practice to define operators in two steps, like shown in the example. The first definition contains the function's logic. The second definition is merely an alias of the first one. This provides a default pronunciation to the operator and clearly indicates that the operator is syntactic sugar : a means to ease
Advanced Topics -
Operators
Allowed Operators
Don't define wide scope operators. Restrict their scope to module or function. Don't use many of them. Before defining a custom binary operator, check that the symbol is not already used. This can be done in two ways: By surrounding the candidate symbol with parentheses in UTo
Advanced Topics -
Understanding the Garbage Collector
Generational Garbage Collection
different memory layouts and garbage-collection algorithms for the major and minor heaps to account for this generational difference. We'll explain how they differ in more detail next. A typical functional programming style means that young blocks tend to die young and old blocks tend to stay around for longer than young ones. This is often referred to as the generational hypothesis . A small
Runtime & Compiler -
Understanding the Garbage Collector
The Gc Module and OCAMLRUNPARAM
ttings. The format of OCAMLRUNPARAM is documented in the OCaml manual . OCaml provides several mechanisms to query and alter the behavior of the runtime system. The Gc module provides this functionality from within OCaml code, and we'll frequently refer to it in the rest of the chapter. As with several other standard library modules, Core alters the Gc interface from the standard OCaml
Runtime & Compiler -
Understanding the Garbage Collector
Understanding Allocation
<div class="note"> These poll points check ptr against limit and developers should expect them to be placed at the start of every function and the back edge of loops. The compiler includes a dataflow pass that removes all but the minimum set of points necessary to ensure these checks happen in a bounded amount of time. It is possib
Runtime & Compiler -
Understanding the Garbage Collector
Setting the Size of the Minor Heap
t at the cost of a bigger memory profile). This setting can be overridden via the s=<words> argument to OCAMLRUNPARAM . You can change it after the program has started by calling the Gc.set function:
Runtime & Compiler -
Understanding the Garbage Collector
The Mutable Write Barrier
install the Core benchmarking suite via opam install core_bench before you compile this code: The OCaml compiler keeps track of any mutable types and adds a call to the runtime caml_modify function before making the change. This checks the location of the target write and the value it's being changed to, and ensures that the remembered set is consistent. Although the write barrier is reas
Runtime & Compiler -
Options
The Standard Library Option Module
Most of the functions in this section, as well as other useful ones, are provided by the OCaml standard library in the Stdlib.Option module.
Data Structures -
Monads
Example: The Lwt Monad
that we saw before involves creating references, but those references are completely hidden behind the monadic interface. Moreover, we know that bind involves registering callbacks, but that functionality (which as you might imagine involves maintaining collections of callbacks) is entirely encapsulated. And Lwt.Infix.( >>= ) is a synonym for Lwt.bind , so the library does provide an infi
Data Structures