How to provide an OCaml (let*) operator optionally, to work with old and new compilers? - operators

I have a module MyMonad that provides a bind function as (let*) operator, but also as >>= operator for old-style code.
The idea is that old code can use it as:
let foobar () =
let open MyMonad in
foo "test" >>= fun s ->
bar s 1 >>= fun (a, b) ->
return a + b
and that new code compiled on OCaml >= 4.08 can use it as:
let foobar () =
let open MyMonad in
let* s = foo "test" in
let* a, b = bar s 1 in
return a + b
Inside the module MyMonad.ml, these operators are implemented in a straight forward way:
let (>>=) a f =
...
let (let*) = (>>=)
However, on OCaml <= 4.07, the last line is a syntax error. And the same is true for the val (let*) : ... line in the MyMonad.mli interface file.
This issue occurs especially when this module is meant to be used in BuckleScript (nowadays ReScript) as well, which is based on OCaml 4.06 and where it is not clear when they will upgrade to a later OCaml version.
How can I mark those last lines to be compiled only on OCaml >= 4.08?
Note: I'm aware that I could create two modules, one adding (let*) on top of the other and being excluded on old compilers. But I wonder if there is a more elegant solution.

To answer this question myself, there is indeed to need to stick with >>=, the new syntax can be used via shims with old OCaml compilers and even BuckleScript (nowadays ReScript).
The latter can be achieved as follows:
Create a new OPAM switch into the current directory for the 4.06 OCaml compiler. This is the version on which is the current BuckleScript version is based, and it is needed to convince the shims to actually do something (for more recent compiler versions those would compile to a no-op):
opam switch create -wy --no-install . 4.06.0
Install the ocaml-syntax-shims OPAM package:
opam install -wy ocaml-syntax-shims
Add the following preprocessing line to you bsconfig.json configuration file:
{
"pp-flags": "./_opam/bin/ocaml-syntax-shims -dump-ast",
...
}

Many of the additions to the language or stdlib are followed by backporting libraries usually called *-shims.
For your problem, there is
https://github.com/ocaml-ppx/ocaml-syntax-shims

Related

is ValidatedNel arrow-kt in v1.0 still an Applicative (Functor)?

I understand that in previous versions of Arrow-Kt was an instance of the Applicative typeclass. In the current version 1.0.x, most typeclasses are no longer present/visible (to make the library more accessible, I presume?).
There are some excellent explanations why an error accumulating Validation data type can't be a Monad, for instance Haskell 1 and Haskell 2 and also Scalaz, Cats or arrow-kt. Hoogle also states that
Furthermore, the Monad and Applicative operations should relate as follows:
pure = return
m1 <*> m2 = m1 >>= (x1 -> m2 >>= (x2 -> return (x1 x2)))
My problem is that I can't see an instance of the Applicative Functor instance in the current implementation of Validated in arrow-kt. More precisely, I don't see an ap function anywhere:
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
my intuition tells me that the zip function behaves somewhat similar to a map/ap composition
Haskell/Purescript:
Person <$> validateName first <*> validateName last <*> validateAge age
Kotlin with arrow-kt:
validateName(first).zip(validateName(last), validateAge(age), ::Person)
is zip an ap in disguise? Anything else I might be missing in my reasoning?
Like #LordRaydenMK has already mentioned in a comment zip is ap in disguise to be more in line with the Kotlin Standard Library.
Another strong reason for not having ap in Kotlin is because currying is not 1st class supported by Kotlin as it is in Haskell, and we cannot define multiple parameter lists like in Scala. So far that reason ap is actually quite cumbersome to use, and not user-friendly at all.
So for the sake of user-friendliness, being more idiomatic in Kotlin and decreasing the learning curve Arrow decided to remove ap and offer zip instead.

F# and ILNumerics

I have just downloaded the last version of ILNumerics, to be used in my F# project. Is it possible to leverage on this library in F#? I have tried simple computations and it seems very cumbersome (in F#).
I would like to set up a constrained (or even unconstrained) optimization problem. The usual Rosenbrock function would do and then I will use my own function. I am having hard times in having even an Array being defined. The only kind of array I could define was a RetArray, for example with this code
let vector = ILMath.vector<float>(1.0, 2.0)
The compiler signals that vector is a RetArray; I think this is due to the fact that it is returning from a function (i.e.: ILMath.vector). If I define another similar vector, I can -e.g.- sum vectors, simply writing, for example
let a = ILMath.vector<float>(1.0, 2.0)
let b = ILMath.vector<float>(3.2,2.2)
let c = a + b
and I get
RetArray<float> = seq [4.2; 4.2]
but if I try to retrieve the value of c, again, writing, for example in FSI,
c;;
I get
Error: Object reference not set to an instance of an object.
What is the suggested way of using ILNumerics in F#? Is it possible to use the library natively in F# or I am forced to call my F# code from a C# library to use the whole ILNumerics library? Other than with the problem cited, I have problems in understanding the very basic logic of ILNumerics, when ported in F#.
For example, what would be the F# equivalent of the C# using scope as in the example code, as in:
using (ILScope.Enter(inData)) { ...
}
Just to elaborate a bit on brianberns' answer, there are a couple of things you could do to make it easier for yourself.
I would personally not go the route of defining a custom operator - especially one that overrides an existing one. Instead, perhaps you should consider using a computation expression to work with the ILMath types. This will allow you to hide a lot of the uglyness, that comes when working with libraries making use of non-F# standards (e.g. implicit type conversions).
I don't have access to ILMath, so I have just implemented these dummy alternatives, in order to get my code to compile. I suspect you should be able to just not copy that in, and the rest of the code will work as intended
module ILMath =
type RetArray<'t> = { Values: 't seq }
and Array<'t> = { OtherValues: 't seq } with
static member op_Implicit(x: RetArray<_>) = { OtherValues = x.Values }
static member inline (+) (x1, x2) = { Values = (x1.OtherValues, x2.OtherValues) ||> Seq.map2 (+) }
type ILMath =
static member vector<'t>([<ParamArray>] vs : 't []) = { ILMath.Values = vs }
If you have never seen or implemented a computation expression before, you should check the documentation I referenced. Basically, it adds some nice, syntactic sugar on top of some uglyness, in a way that you decide. My sample implementation adds just the let! (desugars to Bind) and return (desugars to Return, duh) key words.
type ILMathBuilder() =
member __.Bind(x: ILMath.RetArray<'t>, f) =
f(ILMath.Array<'t>.op_Implicit(x))
member __.Return(x: ILMath.RetArray<'t>) =
ILMath.Array<'t>.op_Implicit(x)
let ilmath = ILMathBuilder()
This should be defined and instantiated (the ilmath variable) at the top level. This allows you to write
let c = ilmath {
let! a = vector(1.0, 2.0)
let! b = vector(3.2, 2.2)
return a + b
}
Of course, this implementation adds only support for very few things, and requires, for instance, that a value of type RetArray<'t> is always returned. Extending the ILMathBuilder type according to the documentation is the way to go from here.
The reason that the second access of c fails is that ILNumerics is doing some very unusual memory management, which automatically releases the vector's memory when you might not expect it. In C#, this is managed via implicit conversion from vector to Array:
// C#
var A = vector<int>(1, 2, 3); // bad!
Array<int> A = vector<int>(1, 2, 3); // good
F# doesn't have implicit type conversions, but you can invoke the op_Implicit member manually, like this:
open ILNumerics
open type ILMath // open static class - new feature in F# 5
let inline (!) (x : RetArray<'t>) =
Array<'t>.op_Implicit(x)
[<EntryPoint>]
let main argv =
let a = !vector<float>(1.0, 2.0)
let b = !vector<float>(3.2,2.2)
let c = !(a + b)
printfn "%A" c
printfn "%A" c
0
Note that I've created an inline helper function called ! to make this easier. Every time you create an ILNumerics vector in F#, you must call this function to convert it to an array. (It's ugly, I know, but I don't see an easier alternative.)
To answer your last question, the equivalent F# code is:
use _scope = Scope.Enter(inData)
...

Ocaml unbound module

I'm learning Ocaml language but i have a problem with my modules when i want to compile them.
So, I have a module with the name Door and an other one with the name Case. Into each one, i have a type paramater with the other module :
Door.mli
type t = bool -> Case.u -> t
Case.mli
type u = bool -> Door.t -> u
When i want to compile, i have this error :
File "door.mli", line 14, characters 23-29:
Error: Unbound module Case
Have you got an idea ?
Thanks you
You have two mutually recursive modules, which is always tricky. One way to get them to work is to define them in the same file using module rec A ... and B ....
However, you also have the problem that your types are cyclic. The definition:
type t = bool -> Case.u -> t
is not normally accepted by OCaml either. You can get it to be accepted by specifying -rectypes on the compiler or interpreter command line.
I fear that you'll find these structures to be difficult to work with. The reason they're difficult to define is that they're not usually what you want. You might try starting with more straightforward types if possible.
My advice: get those two types out of door.ml and case.ml, and make Door and Case depend on a common Types module with:
type door = Door of bool -> case -> door
and case = Case of bool -> door -> case

OCaml module types and separate compilation

I am reading through OCaml lead designer's 1994 paper on modules, types, and separate compilation. (kindly pointed to me by Norman Ramsey in another question ). I understand that the paper discusses the origins of OCaml's present module type / signature system. It it, the author proposes opaque interpretation of type declarations in signatures (to allow separate compilation) together with manifest type declarations (for expressiveness). Attempting to put together some examples of my own to demonstrate the kind of problems the OCaml module signature notation is trying to tackle I wrote the following code in two files:
In file ordering.ml (or .mli — I've tried both) (file A):
module type ORDERING = sig
type t
val isLess : t -> t -> bool
end
and in file useOrdering.ml (file B):
open Ordering
module StringOrdering : ORDERING
let main () =
Printf.printf "%b" StringOrdering.isLess "a" "b"
main ()
The idea being to expect the compiler to complain (when compiling the second file) that not enough type information is available on module StringOrdering to typecheck the StringOrdering.isLess application (and thus motivate the need for the with type syntax).
However, although file A compiles as expected, file B causes the 3.11.2 ocamlc to complain for a syntax error. I understood that signatures were meant to allow someone to write code based on the module signature, without access to the implementation (the module structure).
I confess that I am not sure about the syntax: module A : B which I encountered in this rather old paper on separate compilation but it makes me wonder whether such or similar syntax exists (without involving functors) to allow someone to write code based only on the module type, with the actual module structure provided at linking time, similar to how one can use *.h and *.c files in C/C++. Without such an ability it would seem to be that module types / signatures are basically for sealing / hiding the internals of modules or more explicit type checking / annotations but not for separate / independent compilation.
Actually, looking at the OCaml manual section on modules and separate compilation it seems that my analogy with C compilation units is broken because the OCaml manual defines the OCaml compilation unit to be the A.ml and A.mli duo, whereas in C/C++ the .h files are pasted to the compilation unit of any importing .c file.
The right way to do such a thing is to do the following:
In ordering.mli write:
(* This define the signature *)
module type ORDERING = sig
type t
val isLess : t -> t -> bool
end
(* This define a module having ORDERING as signature *)
module StringOrdering : ORDERING
Compile the file: ocamlc -c ordering.mli
In another file, refer to the compiled signature:
open Ordering
let main () =
Printf.printf "%b" (StringOrdering.isLess "a" "b")
let () = main ()
When you compile the file, you get the expected type error (ie. string is not compatible with Ordering.StringOrdering.t). If you want to remove the type error, you should add the with type t = string constraint to the definition of StringOrdering in ordering.mli.
So answer to you second question: yes, in bytecode mode the compiler just needs to know about the interfaces your are depending on, and you can choose which implementation to use at link time. By default, that's not true for native code compilation (because of inter-module optimizations) but you can disable it.
You are probably just confused by the relation between explicit module and signature definitions, and the implicit definition of modules through .ml/.mli files.
Basically, if you have a file a.ml and use it inside some other file, then it is as if you had written
module A =
struct
(* content of file a.ml *)
end
If you also have a.mli, then it is as if you had written
module A :
sig
(* content of file a.mli *)
end =
struct
(* content of file a.ml *)
end
Note that this only defines a module named A, not a module type. A's signature cannot be given a name through this mechanism.
Another file using A can be compiled against a.mli alone, without providing a.ml at all. However, you want to make sure that all type information is made transparent where needed. For example, suppose you are to define a map over integers:
(* intMap.mli *)
type key = int
type 'a map
val empty : 'a map
val add : key -> 'a -> 'a map -> 'a map
val lookup : key -> 'a map -> 'a option
...
Here, key is made transparent, because any client code (of the module IntMap that this signature describes) needs to know what it is to be able to add something to the map. The map type itself, however, can (and should) be kept abstract, because a client shouldn't mess with its implementation details.
The relation to C header files is that those basically only allow transparent types. In Ocaml, you have the choice.
module StringOrdering : ORDERING is a module declaration. You can use this in a signature, to say that the signature contains a module field called StringOrdering and having the signature ORDERING. It doesn't make sense in a module.
You need to define a module somewhere that implements the operations you need. The module definition can be something like
module StringOrderingImplementation = struct
type t = string
let isLess x y = x <= y
end
If you want to hide the definition of the type t, you need to make a different module where the definition is abstract. The operation to make a new module out of an old one is called sealing, and is expressed through the : operator.
module StringOrderingAbstract = (StringOrdering : ORDERING)
Then StringOrderingImplementation.isLess "a" "b" is well-typed, whereas StringOrderingAbstract.isLess "a" "b" cannot be typed since StringOrderingAbstract.t is an abstract type, which is not compatible with string or any other preexisting type. In fact, it's impossible to build a value of type StringOrderingAbstract.t, since the module does not include any constructor.
When you have a compilation unit foo.ml, it is a module Foo, and the signature of this module is given by the interface file foo.mli. That is, the files foo.ml and foo.mli are equivalent to the module definition
module Foo = (struct (*…contents of foo.ml…*) end :
sig (*…contents of foo.mli…*) end)
When compiling a module that uses Foo, the compiler only looks at foo.mli (or rather the result of its compilation: foo.cmi), not at foo.ml¹. This is how interfaces and separate compilation fit together. C needs #include <foo.h> because it lacks any form of namespace; in OCaml, Foo.bar automatically refers to a bar defined in the compilation unit foo if there is no other module called Foo in scope.
¹ Actually, the native code compiler looks at the implementation of Foo to perform optimizations (inlining). The type checker never looks at anything but what is in the interface.

How do I do LISP (apply) in Dart?

The docs say to use f.call.apply(arguments), but that seems to only work for object methods, not functions.
testapply.dart:
#!/usr/bin/env dart
say(a, b, c) {
print("${a}!");
print("${b}!");
print("${c}!");
}
main() {
var args = [1, 2, 3];
say.call.apply(args);
}
Trace:
$ dart testapply.dart
'/Users/andrew/Desktop/testapply.dart': Error: line 11 pos 2: Unresolved identifier 'Function 'say': static.'
say.call.apply(args);
^
Is there a way to do LISP (apply f args) without using objects?
Alternatively, is there a way to dynamically wrap an arbitrary function in an object so that it can be applied using f.call.apply(arguments)?
Alternatively, can Dart curry?
The documentation page you refer to says,
This functionality is not yet implemented, but is specified as part of version 0.07 of the Dart Programming Language Specification. Hopefully it will find its way into our implementations in due course, though it may be quite a while.
That may or may not be the issue...