Confused about F# method signature syntax - functional-programming

I am supposed to write a small program in F# for a uni assignment. One of the exercises says to create a filter method with this signature:
filter : ('a -> bool) -> list<'a> -> list<'a>. But I am struggling to properly interpret this syntax. The docs say the syntax for creating a method is
let [inline] function-name parameter-list [ : return-type ] = function-body. But how does my example fit into this? Is it a function which takes no parameters but returns three values?
The function should filter a list given a predicate which is simple enough, but if it doesn't take any parameters, how should I pass a predicate and list? I am sure I'm missing something major because I can't wrap my head around it.

The documentation you may be referring to tells you how to implement a function. The signature you've been given, however, is the desired function's type. F# types are documented here: https://learn.microsoft.com/dotnet/fsharp/language-reference/fsharp-types
Specifically, the documentation says that in its simplest form, a function has the type parameter-type1 -> return-type, but when it has more parameters, it generally takes the form parameter-type1 -> parameter-type2 -> ... -> return-type.
In F#, functions are values, so the desired filter is a value that happens to be a function. The function should take two inputs: ('a -> bool) and list<'a>, and return a value of the type list<'a>.
One of the inputs is a function in its own right: ('a -> bool).

Technically, this is saying that filter is a function which takes a predicate function of type 'a -> bool and returns a function which takes a list<'a> and returns another value of type list<'a>.
This is because functions only transform one value into another, but either of those values can be a function.
As a practical matter, filter takes two arguments: that predicate function which take one 'a value and returns a boolean, and a list<'a>.

The simplest answer to your question is that that function takes two arguments and returns a value:
('a -> bool) // arg 1
-> list<'a> // arg 2
-> list<'a> // return value
In F#, function arguments can also be thought of as part of the return value because of partially applied functions e.g. you can think of the above as "given the first arg, return back a new function that expects the second arg and gives back the filtered list".
('a -> bool) // arg
-> (list<'a> -> list<'a>) // return value

Related

Why are my types not working out? (Use of type 'a pred = 'a -> bool)

I have been stuck on this question for a while. I've been editing and reviewing and changing the types for a while but I can't get the type checker to accept what I am doing, probably because I don't fully understand the error/where I am going wrong on this. I am working with the type:
type 'a pred = 'a -> bool
I believe this means I can use 'a pred as a shortcut to mean 'a -> bool, so an int going to result in a bool in my case, but I don't fully get how to implement it because I can't find many examples on this online which I have checked for.
My latest version is below, but I am getting a few errors from the checker, including Error: operator and operand do not agree. Would someone be able to explain where my error is, and why?
Edit: I now think there is a mismatch between this function and the rest of the code. The rest of the code requires it to be an 'a, polymorphic, while here I am assuming it is an int. However, I'm not sure how to do this function (check if odd) while keeping it a polymorphic type.
fun isOdd (p : int) : bool =
case p
of 1 => true
| 0 => false
| _ => isOdd (p - 2)
I believe this means I can use 'a pred as a shortcut to mean 'a -> bool
That is correct.
In the case of your isOdd predicate, it is an int pred:
> val isOdd = fn : int -> bool
- isOdd : int pred;
> val it = fn : int -> bool
Perhaps your misconception lies in the fact that in spite of expressing : int pred, the result in the REPL is still described as int -> bool? This is because we have only defined a type alias, and those tend reduce to their non-aliased form in SML.
Or perhaps your misconception lies in the 'a reducing to some concrete value? You can operate with 'a pred by not referring to concrete values of 'a. For example, if you want to filter an 'a list for only values that are true for a given 'a pred, then the standard function List.filter will have the type:
- List.filter : 'a pred -> 'a list -> 'a list;
> val 'a it = fn : ('a -> bool) -> 'a list -> 'a list
I'm not sure how to do this function (check if odd) while keeping it a polymorphic type.
I'm not sure, either.
Oddness is a property of integers, not arbitrary types 'a.
You would need to extend the meaning of "odd" to any type first. Then you would need some kind of overloading, since the oddness of every type presumably isn't determined by the same mechanism. I'm pretty sure this is a side-track caused by one or two confusions.

Given several Option<'a> values, is there a well-known pattern for chaining several 'a -> 'b -> 'b functions?

I have a series of functions 'arg -> 'entity -> 'entity to update an immutable entity.
I have a series of corresponding 'arg option arguments where if the argument is Some, I should call the corresponding update function.
I have currently implemented it like this:
// General utility function
// ('a -> 'b -> 'b) -> 'a option -> 'b -> 'b
let ifSome f argOpt entity =
match argOpt with
| Some arg -> f arg entity
| None -> entity
// Function that accepts several option parameters
// (callbackUrl and authHeader are wrapped in option)
let updateWebhook callbackUrl authHeader webhook =
webhook
|> ifSome Webhook.setCallbackUrl callbackUrl
|> ifSome Webhook.setAuthHeader authHeader
I like how simple it is, but as is often the case with my homegrown functional solutions (particularly when the generic function is more generic than suggested by the parameter names I came up with), I get the feeling that this is just a special case of a more general functional concept - that I could use some existing abstractions to perform the same task. I therefore wonder:
Is this a recognized functional pattern? If so, does it have a name, and can I read more about it somewhere?
If not, is there a (hopefully similarly simple) alternative that accomplishes the same using "well-known" functional abstractions/patterns?
This is just Option.fold (or more precisely in this case Option.foldBack). Folds are more generally known as catamorphisms.
let updateWebhook callbackUrl authHeader webhook =
webhook
|> Option.foldBack Webhook.setCallbackUrl callbackUrl
|> Option.foldBack Webhook.setAuthHeader authHeader

How to use memoize over sequence

let memoize (sequence: seq<'a>) =
let cache = Dictionary()
seq {for i in sequence ->
match cache.TryGetValue i with
| true, v -> printf "cached"
| false,_ -> cache.Add(i ,i)
}
I will call my memoize function inside this function :
let isCached (input:seq<'a>) : seq<'a> = memoize input
If the given sequence item is cached it should print cached otherwise it will continue to add sequence value to cache.
Right now I have problems with types.
When I try to call my function like this :
let seq1 = seq { 1 .. 10 }
isCached seq1
It throws an error
"The type int does not match the type unit"
I want my function to work generic even though I return printfn. Is it possible to achieve that? And while adding value to the cache is it appropriate to give the same value to tuple?
eg:
| false,_ -> cache.Add(i ,i)
I think the problem is that your memoize function does not actually return the item from the source sequence as a next element of the returned sequence. Your version only adds items to the cache, but then it returns unit. You can fix that by writing:
let memoize (sequence: seq<'a>) =
let cache = Dictionary()
seq {for i in sequence do
match cache.TryGetValue i with
| true, v -> printf "cached"
| false,_ -> cache.Add(i ,i)
yield i }
I used explicit yield rather than -> because I think that makes the code more readable. With this change, the code runs as expected for me.
Tomas P beat me to the punch, but I'll post this up anyway just in case it helps.
I'm not too sure what you are trying to achieve here, but I'll say a few things that I think might help.
Firstly, the type error. Your isCached function is defined as taking a seq of type 'a, and returning a seq of type 'a. As written in your question, right now it takes a seq of type 'a, and returns a sequence of type unit. If you try modifying the output specification to seq<'b> (or actually just omitting it altogether and letting type inference do it), you should overcome the type error. This probably still won't do what you want, since you aren't actually returning the cache from that function (you can just add cache as the final line to return it). Thus, try something like:
let memoize (sequence: seq<'a>) =
let cache = Dictionary()
for i in sequence do
match cache.TryGetValue i with
| true, v -> printf "cached"
| false,_ -> cache.Add(i ,i)
cache
let isCached (input:seq<'a>) : seq<'b> = memoize input
All this being said, if you are expecting to iterate over the same sequence a lot, it might be best just to use the library function Seq.cache.
Finally, with regards to using the value as the key in the dictionary... There's nothing stopping you from doing that, but it's really fairly pointless. If you already have a value, then you shouldn't need to look it up in the dictionary. If you are just trying to memoize the sequence, then use the index of the given element as the key. Or use the specific input as the key and the output from that input as the value.

How to use LIST_SORT function in SML/NJ?

I don't get how to use properly the function to sort a list in SML/NJ (Standard ML of New Jersey).
This is the manual : here
make a use case example,
e.g. sort ([1,9,3,4]); in order to get [1,3,4,9].
Very briefly, following is the syntax:
ListMergeSort.sort (fn(x,y)=> x>y) [3,5,6,7,4,3,7,9,1,2,3];
Explanation:
ListMergeSort: Because that is the structure provided as it comes in the documentation:
Synopsis
signature LIST_SORT
structure ListMergeSort : LIST_SORT
The LIST_SORT signature specifies an interface for the applicative sorting of lists.
Thereafter, the sort function requires two parameters as is evident from the interface:
val sort : (('a * 'a) -> bool) -> 'a list -> 'a list
a function that accepts two parameters and returns a boolean: (('a * 'a) -> bool)
This is exemplified by the anonymous function I defined on the fly:
fn(x,y)=> x>y
It accepts two parameters and it returns a boolean. These two parameters are provided by the sort function who will pass in the elements of the list to be sorted.
a list that requires to be sorted, e.g.: [3,5,6,7,4,3,7,9,1,2,3]

Does "Value Restriction" practically mean that there is no higher order functional programming?

Does "Value Restriction" practically mean that there is no higher order functional programming?
I have a problem that each time I try to do a bit of HOP I get caught by a VR error. Example:
let simple (s:string)= fun rq->1
let oops= simple ""
type 'a SimpleType= F of (int ->'a-> 'a)
let get a = F(fun req -> id)
let oops2= get ""
and I would like to know whether it is a problem of a prticular implementation of VR or it is a general problem that has no solution in a mutable type-infered language that doesn't include mutation in the type system.
Does “Value Restriction” mean that there is no higher order functional programming?
Absolutely not! The value restriction barely interferes with higher-order functional programming at all. What it does do is restrict some applications of polymorphic functions—not higher-order functions—at top level.
Let's look at your example.
Your problem is that oops and oops2 are both the identity function and have type forall 'a . 'a -> 'a. In other words each is a polymorphic value. But the right-hand side is not a so-called "syntactic value"; it is a function application. (A function application is not allowed to return a polymorphic value because if it were, you could construct a hacky function using mutable references and lists that would subvert the type system; that is, you could write a terminating function type type forall 'a 'b . 'a -> 'b.
Luckily in almost all practical cases, the polymorphic value in question is a function, and you can define it by eta-expanding:
let oops x = simple "" x
This idiom looks like it has some run-time cost, but depending on the inliner and optimizer, that can be got rid of by the compiler—it's just the poor typechecker that is having trouble.
The oops2 example is more troublesome because you have to pack and unpack the value constructor:
let oops2 = F(fun x -> let F f = get "" in f x)
This is quite a but more tedious, but the anonymous function fun x -> ... is a syntactic value, and F is a datatype constructor, and a constructor applied to a syntactic value is also a syntactic value, and Bob's your uncle. The packing and unpacking of F is all going to be compiled into the identity function, so oops2 is going to compile into exactly the same machine code as oops.
Things are even nastier when you want a run-time computation to return a polymorphic value like None or []. As hinted at by Nathan Sanders, you can run afoul of the value restriction with an expression as simple as rev []:
Standard ML of New Jersey v110.67 [built: Sun Oct 19 17:18:14 2008]
- val l = rev [];
stdIn:1.5-1.15 Warning: type vars not generalized because of
value restriction are instantiated to dummy types (X1,X2,...)
val l = [] : ?.X1 list
-
Nothing higher-order there! And yet the value restriction applies.
In practice the value restriction presents no barrier to the definition and use of higher-order functions; you just eta-expand.
I didn't know the details of the value restriction, so I searched and found this article. Here is the relevant part:
Obviously, we aren't going to write the expression rev [] in a program, so it doesn't particularly matter that it isn't polymorphic. But what if we create a function using a function call? With curried functions, we do this all the time:
- val revlists = map rev;
Here revlists should be polymorphic, but the value restriction messes us up:
- val revlists = map rev;
stdIn:32.1-32.23 Warning: type vars not generalized because of
value restriction are instantiated to dummy types (X1,X2,...)
val revlists = fn : ?.X1 list list -> ?.X1 list list
Fortunately, there is a simple trick that we can use to make revlists polymorphic. We can replace the definition of revlists with
- val revlists = (fn xs => map rev xs);
val revlists = fn : 'a list list -> 'a list list
and now everything works just fine, since (fn xs => map rev xs) is a syntactic value.
(Equivalently, we could have used the more common fun syntax:
- fun revlists xs = map rev xs;
val revlists = fn : 'a list list -> 'a list list
with the same result.) In the literature, the trick of replacing a function-valued expression e with (fn x => e x) is known as eta expansion. It has been found empirically that eta expansion usually suffices for dealing with the value restriction.
To summarise, it doesn't look like higher-order programming is restricted so much as point-free programming. This might explain some of the trouble I have when translating Haskell code to F#.
Edit: Specifically, here's how to fix your first example:
let simple (s:string)= fun rq->1
let oops= (fun x -> simple "" x) (* eta-expand oops *)
type 'a SimpleType= F of (int ->'a-> 'a)
let get a = F(fun req -> id)
let oops2= get ""
I haven't figured out the second one yet because the type constructor is getting in the way.
Here is the answer to this question in the context of F#.
To summarize, in F# passing a type argument to a generic (=polymorphic) function is a run-time operation, so it is actually type-safe to generalize (as in, you will not crash at runtime). The behaviour of thusly generalized value can be surprising though.
For this particular example in F#, one can recover generalization with a type annotation and an explicit type parameter:
type 'a SimpleType= F of (int ->'a-> 'a)
let get a = F(fun req -> id)
let oops2<'T> : 'T SimpleType = get ""

Resources