[cwn] Attn: Development Editor, Latest OCaml Weekly News
Alan Schmitt
alan.schmitt at polytechnique.org
Tue Dec 6 02:40:19 PST 2022
Hello
Here is the latest OCaml Weekly News, for the week of November 29 to
December 06, 2022.
Table of Contents
─────────────────
Optimising an interpreter
Upcoming Dune Feature: (include_subdirs qualified)
AoC 2022 by TJ DeVries
ptime 1.1.0 and mtime 2.0.0
Cool OCaml-based web-frontend for Emacs org-files
Brr 0.0.4
OpenAI OpenGPT writing OCaml
Old CWN
Optimising an interpreter
═════════════════════════
Archive:
<https://discuss.ocaml.org/t/optimising-an-interpreter/10874/6>
Continuing the thread from last week, yallop said
─────────────────────────────────────────────────
I could use MetaOCaml and do staged metaprogramming.
Should be easy and achieve a very respectable speedup but
MetaOCaml is obscure so I assume dev tools would no longer
work?
The tools mostly work.
For example, ocamlfind (with [this package], which is installed
automatically) and dune (see, e.g., this [example]) both support
MetaOCaml.
I don’t know how well Merlin works with MetaOCaml, but it might work
reasonably well if you use attributes rather than quotation syntax
(i.e. `(2 + 3) [@metaocaml.bracket]' rather than `.<2 + 3>.').
Libraries mostly work unmodified (since MetaOCaml is binary-compatible
with OCaml), but a few libraries conflict with MetaOCaml’s additional
syntax (e.g. by using `>.' for float comparison) and need minor
modifications.
[this package]
<https://github.com/ocaml/opam-repository/blob/master/packages/base-metaocaml-ocamlfind/base-metaocaml-ocamlfind.base/opam>
[example]
<https://github.com/yallop/ocaml-reex/blob/94eea88bb06be5e295627f437d7a585bd9d9b0a6/lib/dune#L8-L13>
Upcoming Dune Feature: (include_subdirs qualified)
══════════════════════════════════════════════════
Archive:
<https://discuss.ocaml.org/t/upcoming-dune-feature-include-subdirs-qualified/10891/1>
Rudi Grinberg asked
───────────────────
/Editor’s note: there were many replies, please follow the link above
to read them./
Hello, the dune team is working on adding `(include_subdirs
qualified)' support to dune and would like your feedback on some user
facing details. I’ll explain how the feature works in this post, but
you can also read the initial [feature request] for some background.
[feature request] <https://github.com/ocaml/dune/issues/1084>
Wrapped Libraries
╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
First, let’s review how wrapped libraries work. This is important
because `(include_subdirs qualified)' just generalizes the scheme to
arbitrary directories. Suppose we have the following library:
┌────
│ (library
│ (wrapped true) ;; this is the default. it's added here for clarity
│ (name foolib))
└────
By default, dune will make every single module in this library
available under `Foolib' - e.g. `Foolib.X'. In this example, the
“library interface” module is `Foolib' and it is always present. In
this example, it is generated. But it can also be written by hand:
┌────
│ $ cat foolib.ml
│ (* We can choose to export whatever we want *)
│ module X = X
└────
The advantage of hand writing this interface module is of course
tighter control over the interface of the library. The disadvantage is
that it has to be manually written.
Qualified Subdirectories
╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
The stanza `(include_subdirs qualified)' generalizes the above scheme.
In particular, one may introduce a directory with modules. For
example:
┌────
│ $ ls
│ foo.ml
│ sub/
│ x.ml
│ y.ml
└────
Inside foo.ml, we’ll refer to `Sub.X' and `Sub.Y'. While `x.ml' and
`y.ml' we’ll be able to refer to each other in an unqualified manner
(`X' and `Y'). Naturally, the module `Sub' will also be an interface
module and the user will have the option to write it manually. This is
where we get some options.
Interface Modules for module groups
╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
Given the example above, where should the user write the interface
module for `Sub' and how should it be referred to in dune files? I’ll
list two options and briefly describe their advantages:
• `sub/sub.ml' - this would be most similar to how we handle the
toplevel library interface. It also maintains the invariant that
every directory has at most one interface file.
• `sub.ml' - this module would live in the same directory as `sub/'
and would allow `sub/sub.ml' to exist as `Sub.Sub'. I think this
behavior is more intuitive to users.
Finally, how should we refer to such modules in dune files? For
example, in dune files we can set per module preprocessing or mark
some modules as private. How should we make the `Sub' private?
┌────
│ (library
│ (name foolib)
│ (private_modules foo)
│ ;; or this
│ (private_modules foo.foo))
└────
If the interface modules exists at `sub/sub.ml', then we should
probably just forbid `foo.foo'. While if the interface module is
`sub.ml', both paths are allowed and simplify refer to different
modules (`sub.ml' or `sub/sub.ml').
My questions to the community:
• Which scheme do you think is more natural?
• Do you have any other comments about the feature?
AoC 2022 by TJ DeVries
══════════════════════
Archive: <https://discuss.ocaml.org/t/aoc-2022-by-tj-devries/10898/1>
Emile Rolley announced
──────────────────────
New series of TJ DeVries on Advent of Code with OCaml :slight_smile:
<https://youtube.com/playlist?list=PLep05UYkc6wQwd0-XPGQ5gRHID8YMYIeW>
ptime 1.1.0 and mtime 2.0.0
═══════════════════════════
Archive:
<https://discuss.ocaml.org/t/ann-ptime-1-1-0-and-mtime-2-0-0/10899/1>
Daniel Bünzli announced
───────────────────────
I’d like to announce new releases of ptime and mtime. Ptime and mtime
provide types and clocks for POSIX and monotonic time. A few
highlights:
• Ptime’s non-strict RFC 3339 parsing is further relaxed to parse
`hhmm' and `hh' time zones (strict is `hh:mm'). This is sometimes
found in web services. Strictly speaking it means a larger subset of
ISO 8601 is parsed. Other than that the release adds a few more
convenience API entry points for dealing with years and weekdays,
see the [release notes][ptime-rn] for all the details.
• On Linux and MacOS `Mtime_clock' does now take into account system
sleep time by respectively using `CLOCK_BOOTTIME' and
`mach_continuous_time' (thanks to @BikalGurung for the patch).
• The `Mtime' module suffered a bit of floating point conversion mess
and bugs (thanks to @talex5 for reporting). The functions deprecated
in 1.4.0 have now been removed[^1] and the single point of
conversion with floats are the [`Mtime.Span.{to,of}_float_ns']
functions.
Other changes are described in the release notes for [`ptime'] and
[`mtime'].
• Home pages: [ptime], [mtime]
• Docs & manuals: [ptime], [mtime] or `odig doc ptime mtime'
• Install: `opam install ptime mtime'
Best,
Daniel
[^1]: It seems that this lead to quite a bit of breakage on the
`opam-repository'. Sorry about that I didn’t know there were so many
packages using `mtime'.
A big thanks to my [donators]. I welcome and thank the new donator
@jhw.
[`Mtime.Span.{to,of}_float_ns']
<https://erratique.ch/software/mtime/doc/Mtime/Span/index.html#convert>
[`ptime']
<https://github.com/dbuenzli/ptime/blob/master/CHANGES.md#v110-2022-12-02-zagreb>
[`mtime']
<https://github.com/dbuenzli/mtime/blob/master/CHANGES.md#v200-2022-12-02-zagreb>
[ptime] <https://erratique.ch/software/ptime>
[mtime] <https://erratique.ch/software/mtime>
[ptime] <https://erratique.ch/software/ptime/doc>
[mtime] <https://erratique.ch/software/mtime/doc>
[donators] <https://github.com/sponsors/dbuenzli>
Cool OCaml-based web-frontend for Emacs org-files
═════════════════════════════════════════════════
Archive:
<https://discuss.ocaml.org/t/cool-ocaml-based-web-frontend-for-emacs-org-files/10900/1>
Kiran Gopinathan announced
──────────────────────────
Hey everyone! It’s been a while. Here’s a little thing I’ve been
working on that I thought might be interesting for this community:
*Emacs-viewer*
This is a simple application that presents a web frontend for your org
files in Emacs. Internally, it’s written using Dream for the server
and Bonsai for the web frontend.
The high level idea is that the backend uses the `emacsclient' command
to interact with your `emacs' process, using it to parse and process
an org-mode buffer. The data from `emacs', which is returned as a
s-expression, is parsed by the backend into a common representation
shared between the backend and the frontend. The frontend then renders
this in a prettified format.
<https://global.discourse-cdn.com/business7/uploads/ocaml/original/2X/0/058d8c92d73280331328f13f918d83b18e020e6c.gif>
Wrapping my head around Bonsai took me a bit of time - somewhat
suprisingly, even though I’ve spent a bit of time hacking on
`note'-based web frontends, `bonsai'’s encoding ends up necessitating
quite a different style of development and requires organising
components in fairly different ways to which I was used to.
When I get the time I hope to write up a blog post on a quick start on
both of these frameworks, because I haven’t found a satisfactory
zero-to-working-example guide for either of these frameworks
Anyway, happy to field any questions, or feel free to look at the code
(more gifs at the repo):
<https://github.com/Gopiandcode/emacs-viewer>
Here’s another cool gif of a tag-based search field, which was
probably my first actually reusable non-trivial bonsai component:
<https://global.discourse-cdn.com/business7/uploads/ocaml/original/2X/0/02811e600e154a24a5e35d2ae37d183369981074.gif>
Brr 0.0.4
═════════
Archive: <https://discuss.ocaml.org/t/ann-brr-0-0-4/10913/1>
Daniel Bünzli announced
───────────────────────
There’s a new release of brr. brr is a toolkit for programming
browsers with the js_of_ocaml compiler.
An important note and a few highlights:
• *Important.* The js_of_ocaml devs are making good [progress] towards
support for OCaml 5 effects (yay!). A side effect (haha) is that
the way `brr'’s cookbook suggested to callback from JavaScript to
OCaml breaks – my fault. It also entails a change in the API to
listen and unlisten events. See [this section] of the release notes
and the updated cookbook for [callbacks] and [exposing OCaml to
JavaScript].
`brr' itself has been sanitized, thanks to @vouillon’s for his help.
If you created bindings to callback APIs or exposed OCaml functions
to JavaScript `git grep' for your `Jv.repr' usages and replace them
with the new `Jv.callback' function. If you didn’t and just used
`brr'’s APIs you have nothing to do.
• New [bindings] to [Web MIDI].
• WebWorker safe `brr'. You can now safely link any of brr’s module in
a WebWorker and it won’t explode in your face. Previously we had a
few toplevel module initialization bits that were accessing stuff
that is not available in WebWorkers.
Other than that there are the little additions and tweaks here and
there, all of which you can read about in the [release notes].
[Home page], [Docs and manuals] or `odig doc brr'
Install: `opam install brr'
Best,
Daniel
A big thanks to my [donators].
[progress] <https://github.com/ocsigen/js_of_ocaml/pull/1340>
[this section]
<https://github.com/dbuenzli/brr/blob/master/CHANGES.md#changes-for-upcoming-js_of_ocaml-effect-support>
[callbacks]
<https://erratique.ch/software/brr/doc/ffi_cookbook.html#callback>
[exposing OCaml to JavaScript]
<https://erratique.ch/software/brr/doc/ffi_cookbook.html#export>
[bindings]
<https://erratique.ch/software/brr/doc/Brr_webmidi/index.html>
[Web MIDI]
<https://developer.mozilla.org/en-US/docs/Web/API/Web_MIDI_API>
[release notes]
<https://github.com/dbuenzli/brr/blob/master/CHANGES.md#v004-2022-12-05-zagreb>
[Home page] <https://erratique.ch/software/brr>
[Docs and manuals] <https://erratique.ch/software/brr/doc/>
[donators] <https://github.com/sponsors/dbuenzli>
OpenAI OpenGPT writing OCaml
════════════════════════════
Archive:
<https://discuss.ocaml.org/t/openai-opengpt-writing-ocaml/10916/1>
Boning announced
────────────────
/Editor’s note: this long message started an even longer thread.
Please follow the link above to read it./
Not sure whether this is the right place for this. But I really want
to share this experience with you guys.
TLDR; OpenGTP is chatbot developed by OpenAI. It is *NOT* tailored for
OCaml code generation or even coding. It understand natural language
and context. It knows how to write custom types and use third party
APIs (from `Lwt' to `Cohttp' to `Str' to even `Ppxlib'). It can take
feedback and correct error on error messages. The final code does not
work appropriately, but it is very close and compiles (on a different
thread, I managed to get it to use `Str' which works properly). It
also struggle a little bit on dune vs dune-project.
Please just read the *full and unedited* log. Please remember this is
with a bot. What is your thought on this?
What is Python requirements.txt and please provide an example
╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
Python requirements.txt is a file that lists the Python packages that
your application depends on. It allows you to easily install all of
the necessary packages for your project by running a single command,
rather than having to install each package individually.
Here is an example of a requirements.txt file:
┌────
│ numpy==1.18.5
│ pandas==1.0.5
│ flask==1.1.2
└────
This file specifies that the project requires three packages: numpy,
pandas, and flask. The version number is specified after the package
name and is separated by an equal sign. This ensures that the exact
versions of the required packages are installed.
To install the packages listed in a requirements.txt file, you can use
the `pip' command-line tool. For example, if your requirements.txt
file is in the current directory, you can install all of the required
packages by running the following command:
┌────
│ pip install -r requirements.txt
└────
This command will install the numpy, pandas, and flask packages, as
well as any other packages that those packages depend on. This makes
it much easier to manage the dependencies for your Python project.
Please write a function to parse it in OCaml
╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
Here is an example of a function that can parse a requirements.txt
file in OCaml:
┌────
│ let parse_requirements (contents: string) : (string * string) list =
│ let lines = String.split_on_char '\n' contents in
│ List.filter (fun line -> line <> "") lines
│ |> List.map (fun line ->
│ match String.split_on_char '==' line with
│ | [package; version] -> (package, version)
│ | _ -> raise (Invalid_argument "Invalid requirements.txt format")
│ )
└────
This function takes a string containing the contents of a
requirements.txt file and returns a list of tuples, where each tuple
contains the name of a package and its version number. It splits the
contents of the file on newline characters to get a list of individual
lines, filters out any empty lines, and then uses pattern matching to
extract the package name and version number from each line.
Here is an example of how you could use this function:
┌────
│ let requirements =
│ "numpy==1.18.5
│ pandas==1.0.5
│ flask==1.1.2"
│
│ let packages = parse_requirements requirements
│ (* packages will be a list containing the following tuples:
│ ("numpy", "1.18.5")
│ ("pandas", "1.0.5")
│ ("flask", "1.1.2")
│ *)
└────
This function can be easily modified to handle different formats for
the requirements.txt file, such as specifying package versions using a
different delimiter or allowing for version ranges.
Please use a custom record and make version optional
╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
Here is an example of a function that can parse a requirements.txt
file in OCaml and uses a custom record type to store the package name
and version number:
┌────
│ type package = {
│ name: string;
│ version: string option;
│ }
│
│ let parse_requirements (contents: string) : package list =
│ let lines = String.split_on_char '\n' contents in
│ List.filter (fun line -> line <> "") lines
│ |> List.map (fun line ->
│ match String.split_on_char '==' line with
│ | [name; version] -> { name; version = Some version }
│ | [name] -> { name; version = None }
│ | _ -> raise (Invalid_argument "Invalid requirements.txt format")
│ )
└────
This function is similar to the previous example, but instead of
returning a list of tuples, it returns a list of `package' records.
The `package' record has two fields: `name', which is a string
containing the name of the package, and `version', which is an
optional string containing the version number of the package.
Here is an example of how you could use this function:
┌────
│ let requirements =
│ "numpy==1.18.5
│ pandas==1.0.5
│ flask==1.1.2"
│
│ let packages = parse_requirements requirements
│ (* packages will be a list containing the following records:
│ { name = "numpy"; version = Some "1.18.5" }
│ { name = "pandas"; version = Some "1.0.5" }
│ { name = "flask"; version = Some "1.1.2" }
│ *)
└────
This function can be easily modified to handle different formats for
the requirements.txt file, such as specifying package versions using a
different delimiter or allowing for version ranges.
What is the dune file of this
╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
The dune file is a configuration file used by Dune, a build system for
OCaml. It specifies the structure and dependencies of an OCaml
project, as well as the build rules and flags that should be used.
Here is an example of a dune file for a simple OCaml project:
┌────
│ (executable
│ (name my_project)
│ (libraries stdio)
│ (preprocess (pps ppx_deriving.std)))
└────
This dune file defines an executable named `my_project' that depends
on the `stdio' library and uses the `ppx_deriving.std' preprocessor.
It also specifies that the project should be built using the default
build rules and flags.
You can use the `dune build' command to build the project defined in
this dune file. This will compile the source code, link the resulting
object files, and produce an executable binary file.
The dune file for a project can be quite complex, with multiple
libraries and executables, custom build rules and flags, and support
for other languages and tools. However, the basic structure is similar
to the example above.
Please write a pretty printer of type package list
╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
Here is an example of a function that can pretty-print a list of
`package' records in OCaml:
┌────
│ let print_package_list (packages: package list) : unit =
│ List.iter (fun { name; version } ->
│ match version with
│ | Some v -> Printf.printf "%s==%s\n" name v
│ | None -> Printf.printf "%s\n" name
│ ) packages
└────
This function takes a list of `package' records and iterates over each
record, printing its name and version number (if it has one). It uses
the `Printf.printf' function to print each package in the format used
by requirements.txt files, with the package name followed by the
version number (if specified) and separated by an equal sign.
Here is an example of how you could use this function:
┌────
│ let packages = [
│ { name = "numpy"; version = Some "1.18.5" };
│ { name = "pandas"; version = Some "1.0.5" };
│ { name = "flask"; version = None };
│ ]
│
│ print_package_list packages
│ (* This will print the following to the console:
│ numpy==1.18.5
│ pandas==1.0.5
│ flask
│ *)
└────
This function can be easily modified to handle different formats for
printing the package records, such as using a different delimiter for
the version number or omitting the version number altogether.
Can you write a test for parse_requirements
╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
Here is an example of a unit test for the `parse_requirements'
function in OCaml using the `OUnit2' testing framework:
┌────
│ open OUnit2
│
│ let parse_requirements = (* code for parse_requirements goes here *)
│
│ let tests = [
│ (* Test parsing of a requirements.txt file with three packages and version numbers *)
│ "three-package-file" >:: (fun _ ->
│ let requirements =
│ "numpy==1.18.5
│ pandas==1.0.5
│ flask==1.1.2"
│ in
│ let expected = [
│ { name = "numpy"; version = Some "1.18.5" };
│ { name = "pandas"; version = Some "1.0.5" };
│ { name = "flask"; version = Some "1.1.2" };
│ ] in
│ assert_equal (parse_requirements requirements) expected
│ );
│
│ (* Test parsing of a requirements.txt file with three packages and no version numbers *)
│ "three-package-file-no-versions" >:: (fun _ ->
│ let requirements =
│ "numpy
│ pandas
│ flask"
│ in
│ let expected = [
│ { name = "numpy"; version = None };
│ { name = "pandas"; version = None };
│ { name = "flask"; version = None };
│ ] in
│ assert_equal (parse_requirements requirements) expected
│ );
│
│ (* Test parsing of an empty requirements.txt file *)
│ "empty-file" >:: (fun _ ->
│ let requirements = "" in
│ let expected = [] in
│ assert_equal (parse_requirements requirements) expected
│ );
│ ]
│
│ let suite = "parse_requirements_test_suite" >::: tests
│
│ let _ = run_test_tt_main suite
└────
This test suite defines three unit tests for the `parse_requirements'
function: one that tests parsing a requirements.txt file with three
packages and version numbers, one that tests parsing a
requirements.txt file with three packages and no version numbers, and
one that tests parsing an empty requirements.txt file. Each test uses
the `assert_equal' function to compare the result of calling
`parse_requirements' with the expected result and reports any
differences.
To run this test suite, you can use the `dune runtest' command. This
will compile the test suite and run all of the tests, printing the
results to the console. If any of the tests fail, the output will
indicate which tests failed and why.
What is the dune file of this test
╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
Here is an example of a dune file for the unit test suite described
above:
┌────
│ (executable
│ (name parse_requirements_test)
│ (libraries oUnit)
│ (preprocess (pps ppx_deriving.std)))
└────
This dune file defines an executable named `parse_requirements_test'
that depends on the `oUnit' library and uses the `ppx_deriving.std'
preprocessor. It specifies that the test suite should be built using
the default build rules and flags.
To build and run the test suite, you can use the following commands:
┌────
│ dune build parse_requirements_test.exe
│ ./_build/default/parse_requirements_test.exe
└────
This will compile the test suite and produce an executable binary
file, which you can then run to execute the tests. The output of the
tests will be printed to the console, indicating whether the tests
passed or failed.
Please also provide a `dune-project' file for this
╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
Here is an example of a `dune-project' file for the OCaml project that
includes the `parse_requirements' function and the unit test suite
described above:
┌────
│ (lang dune 2.0)
│
│ (name parse_requirements)
│
│ (library
│ (name parse_requirements)
│ (public_name parse_requirements))
│
│ (executable
│ (name parse_requirements_test)
│ (libraries oUnit parse_requirements)
│ (preprocess (pps ppx_deriving.std)))
│
│ (rule
│ (targets parse_requirements.install)
│ (action (progn
│ (install parse_requirements)
│ (install parse_requirements_test))))
└────
This `dune-project' file defines a library named `parse_requirements'
that contains the code for the `parse_requirements' function, and an
executable named `parse_requirements_test' that contains the unit test
suite for the `parse_requirements' function. It also specifies that
the `parse_requirements' library should be installed when the
`parse_requirements.install' target is built.
To build and install the `parse_requirements' library and the
`parse_requirements_test' executable, you can use the following
commands:
┌────
│ dune build parse_requirements.install
│ dune install parse_requirements.install
└────
This will compile the `parse_requirements' library and the
`parse_requirements_test' executable, and then install the
`parse_requirements' library to the default location. You can then use
the `parse_requirements' library in other OCaml projects by adding it
as a dependency in the `dune-project' file and running `dune build' to
build the project. You can also run the `parse_requirements_test'
executable to test the `parse_requirements' function.
I am getting error “File ”parse_requirements_test.ml“, line 12, characters 34-35: 12 | match String.split_on_char ‘==’ line with ^ Error: Syntax error”
╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
The error you are seeing is likely due to a syntax error in the
`parse_requirements' function. In OCaml, strings must be surrounded by
double quotes (`"'), not single quotes (`''). It looks like the
`String.split_on_char' function is being called with a single-quoted
character, which is causing a syntax error.
Here is the corrected version of the `parse_requirements' function
that should fix the syntax error:
┌────
│ let parse_requirements (contents: string) : (string * string) list =
│ let lines = String.split_on_char '\n' contents in
│ List.filter (fun line -> line <> "") lines
│ |> List.map (fun line ->
│ match String.split_on_char '==' line with
│ | [package; version] -> (package, version)
│ | _ -> raise (Invalid_argument "Invalid requirements.txt format")
│ )
└────
In this version of the `parse_requirements' function, the character
passed to the `String.split_on_char' function is a double quote (`"'),
which is the correct syntax in OCaml. This should fix the syntax error
you were seeing.
If you are still experiencing errors, please let me know and I will
try to help you further.
But split_on_char takes a char instead of string
╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
You are correct that the `String.split_on_char' function takes a
`char' argument, not a `string' argument. In OCaml, a `char' is a
single character, represented by a single quote followed by the
character (e.g. `'a'', `'b'', `'c'').
In the previous version of the `parse_requirements' function, the
`String.split_on_char' function was called with a single-quoted
character (`'==''), which is not a valid `char' value in OCaml. This
caused a syntax error.
To fix this error, you can simply pass the `'='' character to the
`String.split_on_char' function instead. This will split the string on
the `=' character, which is the delimiter used in requirements.txt
files to separate the package name and version number. Here is the
corrected version of the `parse_requirements' function:
┌────
│ let parse_requirements (contents: string) : (string * string) list =
│ let lines = String.split_on_char '\n' contents in
│ List.filter (fun line -> line <> "") lines
│ |> List.map (fun line ->
│ match String.split_on_char '=' line with
│ | [package; version] -> (package, version)
│ | _ -> raise (Invalid_argument "Invalid requirements.txt format")
│ )
└────
In this version of the `parse_requirements' function, the
`String.split_on_char' function is called with the `'='' character,
which is a valid `char' value. This should fix the error you were
seeing.
I hope this helps! Let me know if you have any other questions.
Old CWN
═══════
If you happen to miss a CWN, you can [send me a message] and I’ll mail
it to you, or go take a look at [the archive] or the [RSS feed of the
archives].
If you also wish to receive it every week by mail, you may subscribe
[online].
[Alan Schmitt]
[send me a message] <mailto:alan.schmitt at polytechnique.org>
[the archive] <https://alan.petitepomme.net/cwn/>
[RSS feed of the archives] <https://alan.petitepomme.net/cwn/cwn.rss>
[online] <http://lists.idyll.org/listinfo/caml-news-weekly/>
[Alan Schmitt] <https://alan.petitepomme.net/>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.idyll.org/pipermail/caml-news-weekly/attachments/20221206/f5d07fc5/attachment-0001.html>
More information about the caml-news-weekly
mailing list