Thanks for this useful question! I am curious (if you feel comfortable sharing) your interest in approaching OCaml via Haskell. What do you feel are some of OCaml’s advantages for your use case?
Thanks for this! I’d like to see odig
support some sort of search functionality, that would really help someone like myself get orientated quicker.
At the moment I don’t have a use case in mind - I’ve just heard good things about ocaml and I’m curious to explore more. The language certainly has some cool features I’d like to have in Haskell (module functors, polymorphic variants, labelled arguments…etc), and without the zoo of extensions and exotic type-level things it does feel a bit more “industrial”. But I’m not sure I can give up purity having seen how useful it is in Haskell…
I have been particularly impressed by the Bucklescript project - specifically the quality of the generated JS code - and could see myself using that on the frontend for non-trivial projects.
I’d like to add that at some point aswell, but don’t hold your breath for now.
A low effort improvement with great usability returns would be for odoc
to at least generate per package index pages (like ocamldoc
did), this issue tracks this.
It would definitely be nice to have something like hoogle, with global function name and type signature search. Elm has something like that as well.
Merlin has a search feature, :MerlinSearch
in vim or M-x merlin-search
in emacs.
The command takes a query which is a list of type names prefixed by -
or +
:
-
-
for the type of values you have and the function you are looking for can consume -
+
for values you would like to get.
For instance, :MerlinSearch -int +string
gives you ways to transform an integer to a string:
string_of_int V int -> string
Bytes.create V int -> bytes
BytesLabels.create V int -> bytes
String.create V int -> bytes
StringLabels.create V int -> bytes
Big_int.approx_big_int V int -> Big_int.big_int -> string
Num.approx_num_exp V int -> Num.num -> string
Num.approx_num_fix V int -> Num.num -> string
Ratio.approx_ratio_exp V int -> Ratio.ratio -> string
Ratio.approx_ratio_fix V int -> Ratio.ratio -> string
...
Parametric types are flattened (only variance is considered), so String.concat
can be found with -string -list +string
. I haven’t thought about filtering based on the name of values, but this should be easy to implement in a future version of merlin, e.g. env -string +string
for finding string transformers that contains “env” in their name.
The UI has not seen much work and the search is blocking, which is not super convenient, help is welcome to improve that :).
That’s really cool. I’d like to play around with it on the command line, are there any docs? I looked at https://github.com/ocaml/merlin/blob/master/doc/dev/PROTOCOL.md and ran ocamlmerlin single -commands-help
, but not seeing anything about a search functionality.
Never mind, I figured it out
echo '\n' | ocamlmerlin single search-by-polarity -position 0 -query "-int +string" | less
Output is JSON, so would look better with some formatting:
echo '\n' | ocamlmerlin single search-by-polarity -position 0 -query "-int +string" | jq . | less
Here are two small bash/zsh functions building on @yawaramin’s work that might be useful. They will display a list of functions + the signatures. ocs
will only display the first 10 because I don’t always want to fill my screen where as osca
will list them all.
ocs () { echo '\n' | ocamlmerlin single search-by-polarity -position 0 -query $1 | jq '.value.entries[] | "\(.name) = \(.desc)"' | head -n 10 }
ocsa () { echo '\n' | ocamlmerlin single search-by-polarity -position 0 -query $1 | jq '.value.entries[] | "\(.name) = \(.desc)"' }
Fantastic! Minor quibble, but I’d use :
instead of =
to separate the name and type. Also another option for the output is to pipe to less
.
Does it search through all the opam-installed libraries?
Or just the currently opened project?
Why not support plain type signatures like int -> string, why do you need the - and +?
I will give it a try for sure.
Searching by type signatures would be super useful too.
Honestly, the OCaml community doesn’t have something that come close to Haskell’s hoogle.
Which is really annoying when you know the productivity boost hoogle allows…
Does it search through all the opam-installed libraries?
Or just the currently opened project?
It searches only in the project scope. This is a proof-of-concept, but it can easily be enhanced to do opam-wide search (I didn’t think about it because that I never felt the need).
Also, the search space can easily be indexed (while right now it is doing linear search), so performance should not be a problem at scale. I need to talk to @dbuenzli about that :).
Why not support plain type signatures like int -> string, why do you need the - and +?
With the current spec, the search is directed by variance which more accurately reflects the flow of information than a mere ->
. If it is just about syntax, of course the query language can be reworked, it is just frontend work (similarly, Hoogle does not strictly search by signature and do some approximation).
By relying only on variance, values are found even if they execute in a different monad, are written in a continuation passing-style or need more contexts (e.g. a context value).
Results can then be ranked by relevance (though that bit has subjective elements in it).
Even if the project looks asleep, it may be interesting to mention it here : https://github.com/camlspotter/ocamloscope.2.
That’s really neat, but it’s not clear to me how to search for generic types.
For example, M-x merlin-search RET -'a list +'a
gives me an error:
"exception":"Not_found
Raised at file \"src/ocaml/typing/405/ident.ml\", line 168, characters 6-21
Called from file \"src/ocaml/typing/405/env.ml\", line 183, characters 22-43
Called from file \"src/ocaml/typing/405/env.ml\" (inlined), line 1057, characters 2-57
Called from file \"src/ocaml/typing/405/env.ml\", line 1127, characters 26-50
Called from file \"src/analysis/polarity_search.ml\", line 83, characters 29-52
Called from file \"src/utils/std.ml\", line 100, characters 12-15
Called from file \"src/utils/std.ml\", line 102, characters 23-39
Called from file \"src/analysis/polarity_search.ml\", line 86, characters 17-62
Called from file \"src/frontend/query_commands.ml\", line 403, characters 6-125
Called from file \"src/utils/local_store.ml\", line 29, characters 8-12
Re-raised at file \"src/utils/local_store.ml\", line 37, characters 4-15
Called from file \"src/kernel/mocaml.ml\", line 40, characters 8-38
Re-raised at file \"src/kernel/mocaml.ml\", line 48, characters 4-15
Called from file \"src/frontend/new/new_commands.ml\", line 64, characters 15-53
Called from file \"src/utils/std.ml\", line 654, characters 8-12
Re-raised at file \"src/utils/std.ml\", line 656, characters 30-39
Called from file \"src/ocaml/utils/misc.ml\", line 30, characters 20-27
Re-raised at file \"src/ocaml/utils/misc.ml\", line 30, characters 50-57
Called from file \"src/frontend/new/new_merlin.ml\", line 97, characters 18-54
"
Does the search syntax support this? I had a look at the merlin README and wiki, but didn’t see anything about this feature.
No, type parameters are ignored. Just write -list
.
Aha, so it’s only concrete types? Could I find List.for_all
and List.exists
using this? In this case I have a function 'a -> bool
and a 'a list
and I was wondering if merlin search could handle this.
-list -bool
gives me List.find
as first result.
But adding variable to the query language would be valuable.
hi,
maybe sourcegraph (https://sourcegraph.com/welcome#code-navigation) could help on the case of Base, since it’s at github. Here just used it (https://sourcegraph.com/github.com/janestreet/base@master/-/blob/src/sys0.ml#L35:5-35:11) via the sourcegraph-firefox plugin to look for the ‘symbol’ ‘getenv’, it was helpful