I'm having trouble adding a recursive function to a class.
I can declare the function private no problem above my member declarations using let.
But when I try to make it public using member, it does not compile.
member this.rec mux xs ys =
match xs with
| [] -> ys
| x::xt -> x :: mux ys xt
Thanks for correcting me and pointing me to a proper resource online. I have been reading many tutorials but I can't find this info.
Member functions are always recursive, no rec
keyword required:
member this.mux xs ys =
(and even if there was a rec
keyword, it would go before this
, same way as private
- member rec this.mux ...
)
But once you've declared it as a member, you have to reference it as a member as well - i.e. this.mux
instead of mux
:
member this.mux xs ys =
match xs with
| [] -> ys
| x::xt -> x :: this.mux ys xt
(in response to comment)
let
-bound functions can shadow previously defined identifiers. For example:
let f x = x+5
let f x = x-2
let a = f 5 // a = 3, not 10
This is a perfectly legal thing to do (except at top level in modules), and is frequently used for utilitarian purposes, e.g. sanitizing parameters:
let sendEmail email subject body =
let email = canonicalize email
...
Notice how in this function the first thing I do is clean up the email, and then proceed to do whatever (NOTE: this is not "assigning" new value to the parameter email
, but defining a whole new value that just happens to have the same name).
This new definition of email
is used in the rest of the function instead of the original parameter email
. This is called "shadowing".
Now, notice how this new definition of email
references the old definition of email
. This is only possible because email
is not recursive: the compiler knows that the word email
within the definition of email
refers to the previously defined value, not the one being defined right now.
"But wait" - you say - "what does it even mean for email
to be recursive? Doesn't the term "recursive" only apply to functions?". Well, no. Values can be recursive too, but that's a topic for another time. For now, here's a different example:
let notifyUsers sendEmail log =
let sendEmail name =
log ("Notifying " + name)
sendEmail (name + "@contoso.com")
sendEmail "John"
sendEmail "Mark"
sendEmail "Matthew"
sendEmail "Luke"
In this example, I "shadowed" the function sendEmail
with a new definition that logs the name of the user before calling the original sendEmail
. If I defined my "new" sendEmail
as recursive (i.e. let rec sendEmail name = ...
), this program would result in an infinite loop: the function would just endlessly call itself. But because the function is not recursive, it is able to reference previously-defined value of the same name.
Member functions don't have this problem: you can't shadow a class method, that would be meaningless.
This problem is addressed differently in different languages.
For example, in languages with everything mutable by default, this problem doesn't arise at all: you just mutate the values and that's it... Unless you want to change the type, too - then you're screwed.
For another example, in Haskell, all values are always recursive, and shadowing will cause a warning. As a result, people are forced to use ticks or get creative with naming, or even introduce a monad where none is required.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With