OCaml: Throw away return value in imperative code
Asked Answered
W

1

5

How do I successfully throw away the return value of a function and treat it as if it's returning unit (for side-effects, obviously). The obvious approach is to do this:

let foo = begin
  some_ignored_thing ();
  actual_return
end

However, the compiler complains (with a warning) that the return type of some_ignored_thing isn't unit.

I could invent my own method, such as:

let ignore a = ()

Which seems at least concise and flags that something's going on, but is there anything in the language/stdlib that achieves the same thing? I'd have thought it would be a relatively common use case.

Weave answered 6/3, 2013 at 10:37 Comment(3)
The ignore method is in language, as you defined it.Raynor
Gah! Typical. If you want to stick that as the answer I'll happily accept it.Weave
I can recommend u to use let (_:type) = some_ignored_result () in to add type-checking to your code. It will be helpful if some_ignored_result is not your function and it can be changed after upgrading some library.Contraband
V
11

Indeed, there is an ignore : 'a -> unit function that does exactly this.

The compiler actually knows about ignore and hard-code a specific behavior that is generally very useful, but can occasionally be inconvenient: by default, ignoring a function (anything with a type of the form foo -> bar) will raise a warning.

The reason for this is that forgetting to add the last argument of a function is a relatively common mistake. You may write for example

ignore (List.map (fun x -> foo bar))

while you meant to write

ignore (List.map (fun x -> foo bar) li)

and the effects you expect to see applied are not.

So ignore will raise a warning in this case, which your hand-coded let ignore x = () does not do. People also sometimes write

let _ = foo in ...

to ignore foo, but this suffer from the same downside (it's easy to be wrong about what the type actually is). Kakadu recommends to use a type annotation there, and that's a reasonable advice.

(Some people also use let _ = ... for the "main" expression of their program. I recommend to rather use let () = ... for this same reason that it forces more type precision.)

Finally, some people prefer to use the let _ = ... form because they are in situations where using ; would force them to add parentheses or begin..end. I recommend that you always add parentheses or begin..end in these cases, because it's easy to shoot yourself in the foot with that -- obscure precedence rules for if..then..else.. for example.

Vivacious answered 6/3, 2013 at 11:12 Comment(4)
Nit: Why would anybody in their sane mind ever write ignore (List.map (fun x -> e) l) instead of List.iter (fun x -> ignore e) l?Creekmore
Come on, it was an example.Unpaid
I wondered the same thing when writing this example, yet was too lazy to pick a better one. Yet I seemed to thinly remember that I had in fact encountered this situation before. So either it was with another type that had a map but no iter in the standard library, or there is a worse justification: the mapping function was already defined as a value (rather than a function literal), and in absence of a composition operator in the standard library (a sad, but realistic assumption), it's in fact (slightly) more convenient to ignore (map f li) than to iter (ignore . f) li. Dubious.Vivacious
Not from the memory usage standpoint. you're better of with the iter version. Unless there would be a reason for allocating values on purpose, just to ignore the final result?Estheresthesia

© 2022 - 2024 — McMap. All rights reserved.