Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Out of interest: why is it this way? In a lot of other languages (e.g. Java or Python), you don't need to do this. Can't the compiler just figure out that a function refers to another function that's defined later in the same scope? Clojure also requires you to declare a function manually, so I guess it's not completely unheard of, but I'm curious if there's a technical reason or if it's just a more or less arbitrary choice.


I guess for historical and stylistic reasons the OCaml people wanted to allow redefining variables while using the old values in the definition.

So you can say

    let process data =
      let data = sanitize data in
      f(data)
instead of

    let process data0 =
      let data1 = sanitize data0 in
      f(data1)
And because OCaml uses the same let syntax for variables and functions, this also lets you to

    let f x = x * x
    let f x = f (f x)
    
    # now f(3) will be 81
So we can define new f using the definition of old f.

In some cases I can see the point of overwriting variables, instead of using new names like data0, data1, data2, but in the case of functions, redefining functions while utilizing the previous definition in the body of new definition will probably not catch on.

But anyway, because this is possible, OCaml needs another way to signify the that f used in the definition of f is not meant to refer to a previous definition, but the current one.

Hence, let rec.

Also, while marking a single function recursive maybe does not make much difference when reading source code, it's kind of nice to read code when a group of mutually recursive functions is explicitly marked as such.


It's actually quite nice to have to explicitly declare when binding scopes are recursive. It's an easy bug to make on accident otherwise.

Additionally, a recursive binding (behind the scenes) is semantically much more complex as it's the effect of having a fixed-point operator called on a higher-order function. It's nice to have to make a specific syntactic call out to have this happen.


I weakly agree, having been frustrated by both sides of the issue.


I really wish Haskell used `let rec`. It's really easy to accidentally write an infinite loop when all lets are rec, but if you forget the rec you almost certainly will get a name or type error.

Maybe I'd hate it after a day, but I think I wouldn't.


In my experience, both errors happen rarely, but both happen, and unintended-rec is much harder to track down.


You need it due to type inference, otherwise the engine cannot infer all the types properly.


I don't think this is true. Because: Standard ML does not have let rec, but can do type inference just fine.


https://realworldocaml.org/v1/en/html/variables-and-function...

"OCaml distinguishes between nonrecursive definitions (using let) and recursive definitions (using let rec) largely for technical reasons: the type-inference algorithm needs to know when a set of function definitions are mutually recursive, and for reasons that don't apply to a pure language like Haskell, these have to be marked explicitly by the programmer."


Hmm, yes.

Depends on whether /u/hencq asked about why rec is needed, or why and is needed.

I answered above, why rec. And you answered why an explicit grouping of mutually recursive functions using and is needed. And true, this is needed for type inference. And even though Standard ML does not need rec, it does need and.


Ah very interesting. I guess my question was mainly about and, though I hadn't thought about the reasons for rec. It makes sense that that removes a class of errors.

So as a follow-up question: why is type inference impossible without and or what is it about and that makes it possible? For instance, what would happen if I (out of laziness or something) would just insert and everywhere, even for functions that aren't mutually recursive. So, e.g.

  let rec f x = x + 1
  and g y = y * 2
Would type inference somehow fail on that? If not, what's stopping me from writing a version of OCaml where all top level lets are automatically converted to let ... and ... and? (Other than a complete lack of necessary compiler writing skills obviously)


Here is a Stackoverflow answer: http://stackoverflow.com/a/904715/1115446

I don't think anything stops you from defining all functions in a program in one giant let rec ... and ..., but doing that might set some other limitations on how you can structure your code.




Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: