Mutually recursive definition in OCaml - binding

I know that OCaml provide the let rec ... and ... for definition of mutually recursive function. Why I can't use that expression for define mutually recursive value?
In particular, why I can't do something like let rec x=3 and y=x+5 in x but I can do let rec x=3 and y=[x;4] in y?
For the first case, I've try to give me an answer and I think that is a binding "problem", since the binding of the values should be simultaneous, so y can't know the value of x so I can't add it to the value of the constant 5.
It is true?

Neither of your definitions are mutually recursive. You could just as well write them like this:
let x = 3 in
let y = x + 5 in
x
and
let x = 3 in
let y = [x; 4] in
y
Mutually recursive definitions would look like this:
let rec x = y + 3
and y = x + 5 in
x
and
let rec x = 3 :: y
and y = 4:: x in
x
In the second piece of code x is a cyclic list that contains a 3 followed by a 4 and then loops back to the beginning. However the first piece of code doesn't make any sense. How can x equal y + 3 when y equals x + 5? It can't and therefore recursive values can only be defined using constructors of variant types (because that's the only case where a recursive value would not lead to infinite recursion).
So since recursive values can't be defined without constructors and the let rec ... and syntax is not necessary when the value you're trying to define is not recursive, the syntax simply can not be used with anything but constructor applications.

Related

SUMPRODUCT in F# without variables

I have already done some searches, and this question is a duplicate of another post. I am posting this just for future reference.
Is it possible to define SUMPRODUCT without explicitly using variable names x, y?
Original Function:
let SUMPRODUCT x y = List.map2 (*) x y |> List.sum
SUMPRODUCT [1;4] [3;25] // Result: 103
I was hoping to do this:
// CONTAINS ERROR!
let SUMPRODUCT = (List.map2 (*)) >> List.sum
// CONTAINS ERROR!
But F# comes back with an error.
I have already found the solution on another post, but if you have any suggestions please let me know. Thank you.
Function composition only works when the input function takes a single argument. However, in your example, the result of List.map2 (*) is a function that takes two separate arguments and so it cannot be easily composed with List.sum using >>.
There are various ways to work around this if you really want, but I would not do that. I think >> is nice in a few rare cases where it fits nicely, but trying to over-use it leads to unreadable mess.
In some functional languages, the core library defines helpers for turning function with two arguments into a function that takes a tuple and vice versa.
let uncurry f (x, y) = f x y
let curry f x y = f (x, y)
You could use those two to define your sumProduct like this:
let sumProduct = curry ((uncurry (List.map2 (*))) >> List.sum)
Now it is point-free and understanding it is a fun mental challenge, but for all practical purposes, nobody will be able to understand the code and it is also longer than your original explicit version:
let sumProduct x y = List.map2 (*) x y |> List.sum
According to this post:
What am I missing: is function composition with multiple arguments possible?
Sometimes "pointed" style code is better than "pointfree" style code, and there is no good way to unify the type difference of the original function to what I hope to achieve.

Why is the effect of newlines in F# different for certain expressions, and (arguably) counter-intuitive in some of them?

Disclaimer/edit: this is a fairly simple question, but I'm asking it since I'm (still) often confused by evaluation order in F#, esp. with respect to newlines vs. spaces. Trial and error always gets me where I want to, but I don't think you can really understand a language if you have to resort to trial and error.
If I write:
let res x =
x * 1 = x
|> ignore
all's fine, but if I write:
let res x =
x * 1 = x && x * -1 = -x
|> ignore
then the compiler complains (it says it expects bool -> bool, not bool -> unit). I would have expected the newline to act as a separator here.
Adding parentheses helps, and putting it on one line shows that it is evaluated as (X && (Y |> Z)), where X and Y are boolean expressions and Z is any function.
Is this true? And is there a simpler way to find this out? Or better, when is whitespace a significant operator and when not?
To give another example:
let v = x |> fun x -> float x |> fun y -> true
Why is y here of type float and not of type int -> float? This may be obvious, and I sure have programmed thousands of lines that way, it even feels natural, but why?
If the only answer to give is "operator precedence and -> comes before |>", so be it. But I guess/hope there's some more academical or otherwise formal though behind all this (and I still find it odd that && has lower prio than |>, again, I don't understand why and in that case it feels counter-intuitive).
Looking at https://learn.microsoft.com/en-us/dotnet/articles/fsharp/language-reference/symbol-and-operator-reference/#operator-precedence it seems that && has higher precedence than |> so your guess is correct and you need to add parenthesis:
let res x =
(x * 1 = x && x * -1 = -x)
|> ignore
It looks like a new line doesn't act as a separator unless it has a let binding or fall in one of the rules listed here
For example if you take this expression:
let res =
5 + 1
.GetType()
You also get an error, because it applies the . operator to 1 not to the whole expression, so the precedence rules still holds, regardless of the newline.

Going more idiomatic with F#

A very simple example of what I'm trying to do: I know it's possible to write:
let myFunc = anotherFunc
instead of
let myFunc = fun x -> anotherFunc x
I've got two functions fDate1, fDate2 - both of type DateTime -> bool. I need to construct a function that takes a date and verifies if any of fDate1, fDate2 returns true. For now I've invented the following expression:
let myDateFunc = fun x -> (fDate1 x) || (fDate2 x)
Is there a better way of doing these (e.g. using '>>' or high order funcions) ?
I don't think there is anything non-idiomatic with your code. In my opinion, one of the strong points about F# is that you can use it to write simple and easy-to-understand code. From that perspective, nothing could be simpler than writing just:
let myDateFunc x = fDate1 x || fDate2 x
If you had more functions than just two, then it might make sense to write something like:
let dateChecks = [ fDate1; fDate2 ]
let myDateFunc x = dateChecks |> Seq.exists (fun f -> f x)
But again, this only makes sense when you actually need to use a larger number of checks or when you are adding checks often. Unnecessary abstraction is also a bad thing.
You can define a choice combinator:
let (<|>) f g = fun x -> f x || g x
let myDateFunc = fDate1 <|> fDate2
In general, you should use explicit function arguments. The elaborated form of myDateFunc can be written as:
let myDateFunc x = fDate1 x || fDate2 x
As other answers say, your current approach is fine. What is not said is that idiomatic style often produces less readable code. So if you are working in a real project and expect other developers to understand your code, it is not recommended to go too far with unnecessary function composition.
However, for purposes of self-education, you may consider the following trick, a bit in FORTH style:
// Define helper functions
let tup x = x,x
let untup f (x,y) = f x y
let call2 f g (x,y) = f x, g y
// Use
let myFunc =
tup
>> call2 fDate1 fDate2
>> untup (||)
Here, you pass the original value x through a chain of transformations:
make a tuple of the same value;
apply each element of the tuple to corresponding function, obtaining a tuple of results;
"fold" a tuple of booleans with or operator to a single value;
There are many drawbacks with this approach, including that both of fDate1 and fDate2 will be evaluated while it may not be necessary, extra tuples created degrading performance, and more.

F# and lisp-like apply function

For starters, I'm a novice in functional programming and F#, therefore I don't know if it's possible to do such thing at all. So let's say we have this function:
let sum x y z = x + y + z
And for some reason, we want to invoke it using the elements from a list as an arguments. My first attempt was just to do it like this:
//Seq.fold (fun f arg -> f arg) sum [1;2;3]
let rec apply f args =
match args with
| h::hs -> apply (f h) hs
| [] -> f
...which doesn't compile. It seems impossible to determine type of the f with a static type system. There's identical question for Haskell and the only solution uses Data.Dynamic to outfox the type system. I think the closest analog to it in F# is Dynamitey, but I'm not sure if it fits. This code
let dynsum = Dynamitey.Dynamic.Curry(sum, System.Nullable<int>(3))
produces dynsum variable of type obj, and objects of this type cannot be invoked, furthermore sum is not a .NET Delegate.So the question is, how can this be done with/without that library in F#?
F# is a statically typed functional language and so the programming patterns that you use with F# are quite different than those that you'd use in LISP (and actually, they are also different from those you'd use in Haskell). So, working with functions in the way you suggested is not something that you'd do in normal F# programming.
If you had some scenario in mind for this function, then perhaps try asking about the original problem and someone will help you find an idiomatic F# approach!
That said, even though this is not recommended, you can implement the apply function using the powerful .NET reflection capabilities. This is slow and unsafe, but if is occasionally useful.
open Microsoft.FSharp.Reflection
let rec apply (f:obj) (args:obj list) =
let invokeFunc =
f.GetType().GetMethods()
|> Seq.find (fun m ->
m.Name = "Invoke" &&
m.GetParameters().Length = args.Length)
invokeFunc.Invoke(f, Array.ofSeq args)
The code looks at the runtime type of the function, finds Invoke method and calls it.
let sum x y z = x + y + z
let res = apply sum [1;2;3]
let resNum = int res
At the end, you need to convert the result to an int because this is not statically known.

How do I define y-combinator without "let rec"?

In almost all examples, a y-combinator in ML-type languages is written like this:
let rec y f x = f (y f) x
let factorial = y (fun f -> function 0 -> 1 | n -> n * f(n - 1))
This works as expected, but it feels like cheating to define the y-combinator using let rec ....
I want to define this combinator without using recursion, using the standard definition:
Y = λf·(λx·f (x x)) (λx·f (x x))
A direct translation is as follows:
let y = fun f -> (fun x -> f (x x)) (fun x -> f (x x));;
However, F# complains that it can't figure out the types:
let y = fun f -> (fun x -> f (x x)) (fun x -> f (x x));;
--------------------------------^
C:\Users\Juliet\AppData\Local\Temp\stdin(6,33): error FS0001: Type mismatch. Expecting a
'a
but given a
'a -> 'b
The resulting type would be infinite when unifying ''a' and ''a -> 'b'
How do I write the y-combinator in F# without using let rec ...?
As the compiler points out, there is no type that can be assigned to x so that the expression (x x) is well-typed (this isn't strictly true; you can explicitly type x as obj->_ - see my last paragraph). You can work around this issue by declaring a recursive type so that a very similar expression will work:
type 'a Rec = Rec of ('a Rec -> 'a)
Now the Y-combinator can be written as:
let y f =
let f' (Rec x as rx) = f (x rx)
f' (Rec f')
Unfortunately, you'll find that this isn't very useful because F# is a strict language,
so any function that you try to define using this combinator will cause a stack overflow.
Instead, you need to use the applicative-order version of the Y-combinator (\f.(\x.f(\y.(x x)y))(\x.f(\y.(x x)y))):
let y f =
let f' (Rec x as rx) = f (fun y -> x rx y)
f' (Rec f')
Another option would be to use explicit laziness to define the normal-order Y-combinator:
type 'a Rec = Rec of ('a Rec -> 'a Lazy)
let y f =
let f' (Rec x as rx) = lazy f (x rx)
(f' (Rec f')).Value
This has the disadvantage that recursive function definitions now need an explicit force of the lazy value (using the Value property):
let factorial = y (fun f -> function | 0 -> 1 | n -> n * (f.Value (n - 1)))
However, it has the advantage that you can define non-function recursive values, just as you could in a lazy language:
let ones = y (fun ones -> LazyList.consf 1 (fun () -> ones.Value))
As a final alternative, you can try to better approximate the untyped lambda calculus by using boxing and downcasting. This would give you (again using the applicative-order version of the Y-combinator):
let y f =
let f' (x:obj -> _) = f (fun y -> x x y)
f' (fun x -> f' (x :?> _))
This has the obvious disadvantage that it will cause unneeded boxing and unboxing, but at least this is entirely internal to the implementation and will never actually lead to failure at runtime.
I would say it's impossible, and asked why, I would handwave and invoke the fact that simply typed lambda calculus has the normalization property. In short, all terms of the simply typed lambda calculus terminate (consequently Y can not be defined in the simply typed lambda calculus).
F#'s type system is not exactly the type system of simply typed lambda calculus, but it's close enough. F# without let rec comes really close to the simply typed lambda calculus -- and, to reiterate, in that language you cannot define a term that does not terminate, and that excludes defining Y too.
In other words, in F#, "let rec" needs to be a language primitive at the very least because even if you were able to define it from the other primitives, you would not be able to type this definition. Having it as a primitive allows you, among other things, to give a special type to that primitive.
EDIT: kvb shows in his answer that type definitions (one of the features absent from the simply typed lambda-calculus but present in let-rec-less F#) allow to get some sort of recursion. Very clever.
Case and let statements in ML derivatives are what makes it Turing Complete, I believe they're based on System F and not simply typed but the point is the same.
System F cannot find a type for the any fixed point combinator, if it could, it wasn't strongly normalizing.
What strongly normalizing means is that any expression has exactly one normal form, where a normal form is an expression that cannot be reduced any further, this differs from untyped where every expression has at max one normal form, it can also have no normal form at all.
If typed lambda calculi could construct a fixed point operator in what ever way, it was quite possible for an expression to have no normal form.
Another famous theorem, the Halting Problem, implies that strongly normalizing languages are not Turing complete, it says that's impossible to decide (different than prove) of a turing complete language what subset of its programs will halt on what input. If a language is strongly normalizing, it's decidable if it halts, namely it always halts. Our algorithm to decide this is the program: true;.
To solve this, ML-derivatives extend System-F with case and let (rec) to overcome this. Functions can thus refer to themselves in their definitions again, making them in effect no lambda calculi at all any more, it's no longer possible to rely on anonymous functions alone for all computable functions. They can thus again enter infinite loops and regain their turing-completeness.
Short answer: You can't.
Long answer:
The simply typed lambda calculus is strongly normalizing. This means it's not Turing equivalent. The reason for this basically boils down to the fact that a Y combinator must either be primitive or defined recursively (as you've found). It simply cannot be expressed in System F (or simpler typed calculi). There's no way around this (it's been proven, after all). The Y combinator you can implement works exactly the way you want, though.
I would suggest you try scheme if you want a real Church-style Y combinator. Use the applicative version given above, as other versions won't work, unless you explicitly add laziness, or use a lazy Scheme interpreter. (Scheme technically isn't completely untyped, but it's dynamically typed, which is good enough for this.)
See this for the proof of strong normalization:
http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.127.1794
After thinking some more, I'm pretty sure that adding a primitive Y combinator that behaves exactly the way the letrec defined one does makes System F Turing complete. All you need to do to simulate a Turing machine then is implement the tape as an integer (interpreted in binary) and a shift (to position the head).
Simply define a function taking its own type as a record, like in Swift (there it's a struct) :)
Here, Y (uppercase) is semantically defined as a function that can be called with its own type. In F# terms, it is defined as a record containing a function named call, so for calling a y defined as this type, you have to actually call y.call :)
type Y = { call: Y -> (int -> int) }
let fibonacci n =
let makeF f: int -> int =
fun x ->
if x = 0 then 0 else if x = 1 then 1 else f(x - 1) + f(x - 2)
let y = { call = fun y -> fun x -> (makeF (y.call y)) x }
(y.call y) n
It's not supremely elegant to read but it doesn't resort to recursion for defining a y combinator that is supposed to provide recursion all by itself ^^

Resources