Do people use the top level a lot?

So I’ve been using OCaml for some months now, and I never find myself wanting to use the top level. However, there seem like there are a lot of advanced tools (like utop) for working in the top level out there. Do experienced OCamlers use the top level for much? If so, what do you use it for? Am I missing out by not using it?

I use it for three main purposes:

  1. Exploring a new library. It’s very useful to be able to fire up utop and immediately start experimenting with a library I haven’t used before or a major revision to a library I actively use.
  2. Trying out changes to my own libraries. Particularly when the library wraps some external API. This is mostly a repeat of the previous point, focused on making sure my code “feels” the way I expect it to without creating a full project using it.
  3. Data exploration! The same thing a person might do with a tool like ipython.

I use it a lot less now than I did when starting out with OCaml. This is in part due to better tooling for library exploration, like ocp-browser and merlin.


I don’t like languages that don’t have REPLs, for reasons like @hcarty’s. Trying things incrementally without a separate compile and run step can be enormously helpful. I think it’s just a matter of personal working style, though.


This use is very special case, but it adds to @hcarty’s point 2.

The toplevel is extremely helpful when you are writing ppx extensions. If you start utop with utop -dsource you get to see the code that your ppx extensions are producing and play around with them. This is extremely useful for debugging code produced by ppx_extensions!


Working mostly with native compiled files, I cannot use the toplevel for much.
I still use it form time to time to test a one-liner, and often time I regret that previous definitions are not kept from one session to the next.

Let me explain:
Suppose I’m wondering how a small function would behave (what exception would be thrown if I call it with this and that parameters while some file have some particular content, for instance). So I start utop, require some package and open some modules, copy and paste the function, call it, and check. Having my answer, and thinking I’m all done (typical over-optimism) I close the top level and keep going. Quickly thereafter I realise I need to also check in some other case; I fire utop again, and have to go through the history line by line to require the packages again, reopen the modules, redefine the function, all over again.

Some languages (some Lisp, R…) save the current definitions in a local hidden file and I think that would make the toplevel friendlier to people like me.

I see where this is coming from but I don’t quite understand how such a thing should work. It is sort-of easy to re-evaluate the commands you had before but what about side-effects? What about very large current definitions? How to get rid of them again?

the thing is, oftentime it’s not a single definition on a single line but several and that have to be redefined in the same order. Not a big pain but annoying enough.
Also, I often care about the values (be it scalars or functions) not the side effects (actually, in most cases you probably want the values without the side effects), so storing the state is actually more convenient than storing the lines and re-executing them. At least for my workflow.
As to how to get rid of them: I guess by deleting the file it’s stored into?
Very large definitions are indeed a problem, that is probably why R prompts at exit; but I find this annoying and would not recommend it. Ideally, the repl would prompt only if the heap is huge, or there would be a user-configurable size limit.

But anyway, I have no plan to implement any of this so all of the above is just talk everybody is free to disagree with :slight_smile:

There is a way to save the current utop session to a file. I don’t remember the command to do that and I don’t have a computer at hand. But it shouldn’t be too hard to find.

1 Like

I’m not a big fan of using the REPL, but I really like using expect tests as a way to do the same kind of exploratory programming. Here’s an example I wrote up:

Combined with Merlin, which gives you type throwback, I think it’s a pretty good way of doing exploratory programming of various sorts. (Also, shout-out to @antron and his lambdasoup library, which is the one that I use in my example.)



Ha, I’ve long been thinking about a logo like that for Lambda Soup :slight_smile: