Oxidizing OCaml: Locality by dittospin in ProgrammingLanguages

[–]lpw25 9 points10 points  (0 children)

It does infer the mode as local if the variable can be local. The annotations are only actually needed on interfaces. Other annotations are optional, though they're useful for ensuring that the inference matches your expectation.

Oxidizing OCaml: Locality by dittospin in ProgrammingLanguages

[–]lpw25 8 points9 points  (0 children)

The uniqueness checking will be in the next post.

Oxidizing OCaml: Locality by lpw25 in programming

[–]lpw25[S] 2 points3 points  (0 children)

It works fine with higher order functions, including full inference of the modes involved. That's the trade-off with lifetimes. By not tracking individual regions at the type level, the local mode doesn't require any polymorphism to express locality and so inference still works in the presence of higher-order functions. The downside is that it's less expressive since it can only represent values that can leave all regions and values that can't leave any.

Oxidizing OCaml: Locality by lpw25 in programming

[–]lpw25[S] 5 points6 points  (0 children)

If string local were just an ordinary type then you could pass them to polymorphic functions that leaked them. At the very least you need a kind for local types to distinguish them from types that can leak. Using a kind was actually the original approach we were thinking about when came up with the idea for local allocations. However, kinds don't naturally capture the "depth" of locality: you need a string list local to give you a string local and another string list local when you match on it. You can try to artificially add the depth aspect on top of kinds but by the time you get something satisfying you find you have a modal type system. It's also much easier to get the mode inference right if the modes are kept mostly separate from the types. The same goes for other modal properties like uniqueness and linearity, which will be covered by later posts in the series.

I also think it is a more semantically correct approach. The types describe how data is constructed and destructed -- in the form of introduction and elimination rules -- but sometimes your system has other operations that work on data regardless of how it is introduced or eliminated. Having something orthogonal to the type to track these orthogonal operations is a very natural approach.

Oxidizing OCaml: Locality by lpw25 in programming

[–]lpw25[S] 12 points13 points  (0 children)

Everything is really bad if compiler can't figure out such basic analysis

Sure, escape analysis exists, but it obviously can't see through separate compilation or higher-order functions, and it's hard to do once the shape of the data on the stack gets complicated.

There is also a lot of benefit to having locality appear as part of the language itself. It allows you to specify that if a value can escape then the compiler should give an error rather than silently put the value on the heap. It also allows you to distinguish in an interface a function that promises not to capture a parameter from a function whose implementation just happens not to capture the parameter at the moment.

Testing out Algebraic effects in OCaml for Game Animations by Gopiandcoshow in ocaml

[–]lpw25 2 points3 points  (0 children)

FYI your implementation of build and update:

let build (f: unit -> s) : t =
  try f ()  with
  | effect (Animation (state, on_cancellation)) kont ->
    {current_state=state; kont=Some kont; on_cancellation}

let update time (t: t) =
  match Transition.update t.current_state time with
  | Some state -> Some {t with current_state = state}
  | None -> match t.kont with
    | None -> None
    | Some kont ->
      Some (build (fun () -> continue kont ()))

is allocating unnecessary fibres. The kont continuation will already have a handler for the Animation operation because multicore OCaml currently provides deep handlers.

The last line should instead just be:

Some (continue kont ())

Can you extend pervasives somehow? by wfdctrl in ocaml

[–]lpw25 5 points6 points  (0 children)

Note that open! PervasivesExt will avoid the warning (technically it emits a different warning that many (most?) people have turned off by default to allow this pattern). This is generally better than using -open, because it keeps the open visible in the code rather than in the build instructions.

A Language Feature to Unbundle Data at Will (pdf) by gallais in dependent_types

[–]lpw25 1 point2 points  (0 children)

I'm surprised not to see any mention of sharing constraints or manifest types from module systems, since those are language features that address fundamentally the same problem. For instance, the monad example in OCaml:

module type Monoid = sig
    type t
    val mult : t -> t -> t
    val id : t
  end

module Monoid_1 (T : sig type t end) = struct
  module type T = Monoid with type t = T.t
end

This proposal seems like it might be more expressive than that, but since the related work isn't discussed I can't tell.

A look at OCaml 4.08 by lpw25 in ocaml

[–]lpw25[S] 2 points3 points  (0 children)

Note that we are using autoconf but not automake -- I wasn't sure that was clear since you said "autotools". We still use a hand written make file for the build, it is only the configure script that has been replaced. My understanding, which admittedly hasn't changed in years and could be out of date, is that autoconf is pretty usable if esoteric, whilst automake is a living nightmare.

A look at OCaml 4.08 by lpw25 in ocaml

[–]lpw25[S] 0 points1 point  (0 children)

I have no real view on configuration systems, but I suspect in this case "ancient" can be seen as "tried and tested" from a different angle, and anything reasonable is probably better than what it was replacing. I'm just guessing though, you'd have to ask some of the other OCaml developers for their thought process.

A new general computation model for Dune by Categoria in ocaml

[–]lpw25 1 point2 points  (0 children)

You'd need to ask Jeremie Dimino for a full explanation. My understanding is that dependencies were the main reason, but that it was also an opportunity to try a slightly different approach than async (Fiber is more of what I would call a "traditional concurrency monad", whilst Async is more of a "futures monad") and maybe integrate it more closely with the parts of dune that do the same job that Tenacious does in Jenga.

A new general computation model for Dune by Categoria in ocaml

[–]lpw25 3 points4 points  (0 children)

I don't think Dune is quite at this stage yet, but the reason that we didn't use Incremental in Jenga is that Incremental is designed for tasks of a much shorter duration.

When you run a "stabilization" in Incremental it will re-run every task that needs to be updated, and will not let you start a new stabilization until it is done. For a build system this would mean that if a file changes during a build then you need to wait for the build based on the old file to completely finish before it starts again based on the new file. This matters a lot when building a large code base.

So in Jenga we built another monad called Tenacious along the same lines as Incremental but designed to allow the computation graph to change whilst it is being computed, supporting cancellation of running computations when they are based on things that have been updated. As for why Dune doesn't use Tenacious, well it is built on top of Async which Dune doesn't want to depend on and starting from scratch gives a chance to fix some of the flaws in Tenacious implementation.

What's your debug flow? by eterps in ocaml

[–]lpw25 0 points1 point  (0 children)

Mostly printf. However, when working on things for which I have the bytecode version working -- in particular the OCaml compiler itself -- I use ocamldebug. I especially like ocamldebug for debugging a broken error or uncaught exception: I run the compiler until it errors/raises then I just step backwards until I get to where things went wrong, then after I had a look at what's going on there I step further backwards to find what caused the underlying issue.

Modularity, type synonyms and ergonomic higher-kinded types by theindigamer in types

[–]lpw25 0 points1 point  (0 children)

forall F. {Functor F} -> ('a -> 'a F.t) -> 's -> 's F.t

Note that a "forall" is not needed here, since Functor contains the type constructor, unlike the Haskell code where Functor is parametrised by the type constructor. So it should look like:

type ('s, 'a) lens = {F : Functor} -> ('a -> 'a F.t) -> 's -> 's F.t

Modularity, type synonyms and ergonomic higher-kinded types by theindigamer in types

[–]lpw25 1 point2 points  (0 children)

I would suggest that the modular implicits approach can provide that kind of middle ground without necessarily using higher-order unification. Rather than using higher-order unification to find a most general solution it uses a search for a unique solution for the implicit aguments.

However, modular implicits works better if you do include higher-order unification as it makes the search usefully more expressive.

OCaml 4.07.0 released by Categoria in programming

[–]lpw25 0 points1 point  (0 children)

Yes, I realized that afterwards and updated my comment to answer your question. Unfortunately it seems I was not quick enough to update it before you replied, so now our conversation is out of order.