I am new to F# and am trying to chain functions to make a Higher Order Function.
A simplified example is
init returns a tuple
validate accepts a tuple and returns bool
let init : string * string =
("1", "2")
let validate ((a: string), (b: string)) : bool =
a.Equals(b)
let test = init >> validate
ERROR
This expression was expected to have type 'a -> 'b' but here has type 'string * string'
As the answer for Piotr explains, you are getting an error because you have a value and a function. To compose those, you can turn init into a function, but you do not really need to use composition in this case.
If you want to pass a value as an argument to a function, it is typically much simpler to just pass it as an argument:
let res = validate init
Alternatively, if you have a number of functions you want to apply to your input in a sequence, you can do this using the piping operator:
let res = init |> validate
Function composition using >> is a nice functional trick, but I think it is actually much less common in standard F# code than most people think. I use |> all the time, but >> only rarely.
You can only compose functions using the >> combinator. Your first assignment is not a function - it is a binding to a value - your tuple.
You can convert it to a function just by adding empty parameter list () (unit) parameter like this:
let init() : string * string =
("1", "2")
let validate ((a: string), (b: string)) : bool =
a.Equals(b)
let test = init >> validate
let res = test()
Related
I am new to F# and am writing a function to convert a dateTime value to unix timestamp in seconds.
Below is my implementation of such a function (just using builtin function and wrapping it for learning).
let DateTimeToUnix x =
let result = DateTimeOffset(x).ToUnixTimeSeconds
result
Expected return type is: DateTime -> int64
Actual return type is: DateTime-> (unit->int64)
I tried to find similar questions and the closest i found was something like this (F# - The type int is not compatible with type unit)
but unfortunately i don't understand how it is applicable in this case since the return type of the function (ToUnixTimeSeconds) used is int64 and not (unit->int64).
It would be great if someone can point to where to learn about this or can explain the behavior. Thanks a lot for your time.
ToUnixTimeSeconds is a method, not a property. In F# methods are modeled as functions. Parameterless methods are modeled as functions with a single unit-typed parameter. So the type of foo.ToUnixTimeSeconds would be unit -> int64, just like the compiler is telling you.
To actually call that function and obtain a result from it, give it a parameter of the type that it expects - i.e. unit:
let DateTimeToUnix x =
let result = DateTimeOffset(x).ToUnixTimeSeconds ()
result
As a side note, you don't really have to name the intermediate value result:
let DateTimeToUnix x =
DateTimeOffset(x).ToUnixTimeSeconds ()
You have to invoke ToUnixTimeSeconds before returning it in order to get the desired return type:
let DateTimeToUnix x =
let result = DateTimeOffset(x).ToUnixTimeSeconds() // invoke method: ()
result
I have read about continuations and partial applications; I am also aware of the kprintf function.
But I still don't know how to write something like:
let myPrintFunction format variable_length_arguments_list =
let a = sprintf format variable_length_ argument_list
do other things
what would be the syntax this this?
so I could use it like:
myPrintFunction "%s : %i" "hello" 3
Edit:
This is different than How do I implement a method with a variable number of arguments? because that question is asking how to make a method with a variable number of arguments, but the issue I am facing is to pass that variable number of argument to the next function (sprintf) that takes a variable number of arguments too.
Or, at least that's where I suppose the problem is.
The test code, based on the solution proposed by Scott can be found here: https://dotnetfiddle.net/oCzcS9
I want to demonstrate the ksprintf function, because that one accepts a continuation that will allow you to pass on the resulting string to e.g. a log system.
For the purpose of demonstration, let's first create something that can take a single string as input and pass it on, in this case to the console.
let writeStringToConsole (s: string) = Console.WriteLine ("OUTPUT : " + s)
So now, if writeStringToConsole is all we have, how to we make it accept F# formatting?
let printToConsole format = Printf.ksprintf writeStringToConsole format
Example that demonstrates that it works.
type DU = A | B
let i = 7
let s = "thirteen"
let du = B
printToConsole """an int %i and a string "%s" here""" i s
printToConsole """an int %i and a string "%s" and DU %A here""" i s du
// OUTPUT : an int 7 and a string "thirteen" here
// OUTPUT : an int 7 and a string "thirteen" and DU B here
// Note that OUTPUT is also part of the actual output,
// and it demonstrates how you can add e.g. a timestamp
// or line number or something to the output string, without
// it being part of the formatting.
edit: Some additional notes
The format string must be a literal. That's because the literal string must be read at compile time in order to compute the function that must be returned in order to gobble up whatever values/types that follow the format string.
For example, if you do printToConsole "%i %s %A %A" 7 "x" myType yourType, then you'll see int -> string -> MyType -> YourType in the signature of printToConsole where it's used.
There is a way to use plain strings as format strings with this system, but I don't remember how it's done, and anyway it spoils the type safety. It comes in handy when doing internationalization of strings, and your format strings must come from a resource and not F# source due to external translator services.
edit 2 : Wrap e.g. log system
I created an interface to use for various logging systems, which pretty much share the same features.
type ILogger =
...
abstract member Debugf: StringFormat<'h, unit> -> 'h
abstract member Verbosef: StringFormat<'h, unit> -> 'h
abstract member Infof: StringFormat<'h, unit> -> 'h
abstract member Warningf: StringFormat<'h, unit> -> 'h
abstract member Errorf: StringFormat<'h, unit> -> 'h
abstract member Fatalf: StringFormat<'h, unit> -> 'h
Then an implementation for my currently used logging system looks like this.
type internal SiLogger(session: Session) =
let slogf = Printf.ksprintf
...
interface ILogger with
...
member _.Debugf format = slogf session.LogDebug format
member _.Verbosef format = slogf session.LogVerbose format
member _.Infof format = slogf session.LogMessage format
member _.Warningf format = slogf session.LogWarning format
member _.Errorf format = slogf session.LogError format
member _.Fatalf format = slogf session.LogFatal format
And there is a null logger.
let slogf = Printf.ksprintf
let dummyLog _ = () // The parameter is the title string.
let dummy format = slogf dummyLog format
let getNullLogger () =
{ new ILogger with
...
member _.Debugf format = dummy format
member _.Verbosef format = dummy format
member _.Infof format = dummy format
member _.Warningf format = dummy format
member _.Errorf format = dummy format
member _.Fatalf format = dummy format
...
}
open System
let myPrintFunction (format: Printf.StringFormat<_>) ([<ParamArray>] args) =
let a = sprintf format args
a
myPrintFunction "%s : %i" "hello" 3
To add the PrintF as a member function, this is the closest I could get. As you see, I had to pass the format string separately (in the constructor, or I could have used a property setter). I could find no way to pass the format string as the first parameter of the PrintF function as I could for a free function (see my other answer at https://stackoverflow.com/a/58822618/5652483).
Also, if I uncomment the line this.RaiseSomeEvent msg, then it breaks. So I could find no way to enable the PrintF function to have a side effect.
Hopefully, someone else can solve these issues.
type Foo (format: Printf.StringFormat<_>) =
member this.RaiseSomeEvent msg = printf "%s" msg
member this.PrintF ([<ParamArray>] args) =
let msg = sprintf format args
//this.RaiseSomeEvent msg
msg
let foo = Foo("%s : %i")
foo.PrintF "hello" 3
Here is a simple composition of functions in F#
let composedFunction = System.Text.Encoding.UTF8.GetBytes >> Array.length
"test" |> composedFunction
Type inference correctly defines the type of composed function string -> int. But compiler cannot pick correct overload of System.Text.Encoding.UTF8.GetBytes method:
Error FS0041: A unique overload for method 'GetBytes' could not be
determined based on type information prior to this program point. A
type annotation may be needed. Candidates:
System.Text.Encoding.GetBytes(chars: char []) : byte [],
System.Text.Encoding.GetBytes(s: string) : byte []Blockquote
Is there any way to compose correct overload of System.Text.Encoding.UTF8.GetBytes which accepts string parameter?
Or course, I can do following
// declare function which calls correct overload and then use it for compostion
let getBytes (s: string) = System.Text.Encoding.UTF8.GetBytes s
let composedFunction = getBytes >> Array.length
// start composition with ugly lambda
let composedFunction =
(fun (s: string) -> s) >> System.Text.Encoding.UTF8.GetBytes >> Array.length
But I wonder if there is any way without additional function declarations to make the compiler pick right overload according to the inferred string -> int type of composed function?
You can always add annotations:
let composedFunction : string -> _ = System.Text.Encoding.UTF8.GetBytes >> Array.length
or
let composedFunction = (System.Text.Encoding.UTF8.GetBytes : string -> _) >> Array.length
As your example shows, .NET methods do not always compose well - I think the idiomatic approach in such situations is just to use the .NET style when you're dealing with .NET libraries (and use functional style when you're dealing with functional libraries).
In your specific case, I would just define a normal function with type annotation and get the length using the Length member rather than using the function:
let composedFunction (s:string) =
System.Text.Encoding.UTF8.GetBytes(s).Length
The existing answer shows how to get the composition to work with type annotations. Another trick you can do (which I would definitely not use in practice) is that you can add identity function on string to the composition to constrain the types:
let composedFunction = id<string> >> System.Text.Encoding.UTF8.GetBytes >> Array.length
It's fun that this works, but as I said, I would never actually use this, because a normal function as defined above is much easier to understand.
I'm adding a static builder method to a record type like this:
type ThingConfig = { url: string; token : string; } with
static member FromSettings (getSetting : (string -> string)) : ThingConfig =
{
url = getSetting "apiUrl";
token = getSetting "apiToken";
}
I can call it like this:
let config = ThingConfig.FromSettings mySettingsAccessor
Now the tricky part: I'd like to add a second overloaded builder for use from C# (ignore the duplicated implementation for now):
static member FromSettings (getSetting : System.Func<string,string>) : ThingConfig =
{
url = getSetting.Invoke "apiUrl";
token = getSetting.Invoke "apiToken";
}
This works for C#, but breaks my earlier F# call with
error FS0041: A unique overload for method 'FromSettings' could not be determined based on type information prior to this program point. A type annotation may be needed. Candidates: static member ThingConfig.FromSettings : getSetting:(string -> string) -> ThingConfig, static member ThingConfig.FromSettings : getSetting:Func -> ThingConfig
Why can't F# figure out which one to call?
What would that type annotation look like? (Can I annotate the parameter type from the call site?)
Is there a better pattern for this kind of interop? (overloads accepting lambdas from both C# and F#)
Why can't F# figure out which one to call?
Overload resolution in F# is generally more limited than C#. The F# compiler will often, in the interest of safety, reject overloads that C# compiler sees as valid.
However, this specific case is a genuine ambiguity. In the interest of .NET interop, F# compiler has a special provision for lambda expressions: regularly, a lambda expression will be compiled to an F# function, but if the expected type is known to be Func<_,_>, the compiler will convert the lambda to a .NET delegate. This allows us to use .NET APIs built on higher-order functions, such as IEnumerable<_> (aka LINQ), without manually converting every single lambda.
So in your case, the compiler is genuinely confused: did you mean to keep the lambda expression as an F# function and call your F# overload, or did you mean to convert it to Func<_,_> and call the C# overload?
What would the type annotation look like?
To help the compiler out, you can explicitly state the type of the lambda expression to be string -> string, like so:
let cfg = ThingConfig.FromSettings( (fun s -> foo) : string -> string )
A slightly nicer approach would be to define the function outside of the FromSettings call:
let getSetting s = foo
let cfg = ThingConfig.FromSettings( getSetting )
This works fine, because automatic conversion to Func<_,_> only applies to lambda expressions written inline. The compiler will not convert just any function to a .NET delegate. Therefore, declaring getSetting outside of the FromSettings call makes its type unambiguously string -> string, and the overload resolution works.
EDIT: it turns out that the above no longer actually works. The current F# compiler will convert any function to a .NET delegate automatically, so even specifying the type as string -> string doesn't remove the ambiguity. Read on for other options.
Speaking of type annotations - you can choose the other overload in a similar way:
let cfg = ThingConfig.FromSettings( (fun s -> foo) : Func<_,_> )
Or using the Func constructor:
let cfg = ThingConfig.FromSettings( Func<_,_>(fun s -> foo) )
In both cases, the compiler knows that the type of the parameter is Func<_,_>, and so can choose the overload.
Is there a better pattern?
Overloads are generally bad. They, to some extent, obscure what is happening, making for programs that are harder to debug. I've lost count of bugs where C# overload resolution was picking IEnumerable instead of IQueryable, thus pulling the whole database to the .NET side.
What I usually do in these cases, I declare two methods with different names, then use CompiledNameAttribute to give them alternative names when viewed from C#. For example:
type ThingConfig = ...
[<CompiledName "FromSettingsFSharp">]
static member FromSettings (getSetting : (string -> string)) = ...
[<CompiledName "FromSettings">]
static member FromSettingsCSharp (getSetting : Func<string, string>) = ...
This way, the F# code will see two methods, FromSettings and FromSettingsCSharp, while C# code will see the same two methods, but named FromSettingsFSharp and FromSettings respectively. The intellisense experience will be a bit ugly (yet easily understandable!), but the finished code will look exactly the same in both languages.
Easier alternative: idiomatic naming
In F#, it is idiomatic to name functions with first character in the lower case. See the standard library for examples - Seq.empty, String.concat, etc. So what I would actually do in your situation, I would create two methods, one for F# named fromSettings, the other for C# named FromSettings:
type ThingConfig = ...
static member fromSettings (getSetting : string -> string) =
...
static member FromSettings (getSetting : Func<string,string>) =
ThingConfig.fromSettings getSetting.Invoke
(note also that the second method can be implemented in terms of the first one; you don't have to copy&paste the implementation)
Overload resolution is buggy in F#.
I filed already some cases, like this where it is obviously contradicting the spec.
As a workaround you can define the C# overload as an extension method:
module A =
type ThingConfig = { url: string; token : string; } with
static member FromSettings (getSetting : (string -> string)) : ThingConfig =
printfn "F#ish"
{
url = getSetting "apiUrl";
token = getSetting "apiToken";
}
module B =
open A
type ThingConfig with
static member FromSettings (getSetting : System.Func<string,string>) : ThingConfig =
printfn "C#ish"
{
url = getSetting.Invoke "apiUrl";
token = getSetting.Invoke "apiToken";
}
open A
open B
let mySettingsAccessor = fun (x:string) -> x
let mySettingsAccessorAsFunc = System.Func<_,_> (fun (x:string) -> x)
let configA = ThingConfig.FromSettings mySettingsAccessor // prints F#ish
let configB = ThingConfig.FromSettings mySettingsAccessorAsFunc // prints C#ish
So, I can easily write an arbitrary type to JSON with Newtonsoft.Json:
type X = {
Number: decimal
Sequence: decimal
NumList: decimal list
}
let createItem (n, s, nL) =
{Number = n;
Sequence = s;
NumList = nL}
let items =
[
(1M, 1M, [1M; 2M; 3M])
(2M, 2M, [2M; 4M; 6M])
(3M, 3M, [3M; 6M; 9M])
]
|> List.map createItem
open Newtonsoft.Json
open System.IO
let writeToJson (path: string) (obj: 'a) : unit =
let serialized = JsonConvert.SerializeObject(obj)
File.WriteAllText(path, serialized)
writeToJson "xList.json" items
How can I write a function generic enough that I can read a JSON file? In other words, I'd like something like:
let readFromJson (path: string) (t: 'T) =
let convertToQr = File.ReadAllText(path)
Newtonsoft.Json.JsonConvert.DeserializeObject<t list>(convertToQr)
where the second argument is the Type of the object in path, but I don't know how to do that. If I try to use this function as is, I get a compiler error.
How can I declare in the second argument above the type of the thing that is in path? Can I?
Generic parameters, when explicitly defined, are written in angle brackets immediately after function name, before regular parameters:
let readFromJson<'T>(path: string) =
let convertToQr = File.ReadAllText(path)
Newtonsoft.Json.JsonConvert.DeserializeObject<'T list>(convertToQr)
Usage:
readFromJson<string> "/some/file.json"
Alternatively, you can specify the return type of your function, and let the compiler infer all generic parameters and arguments for you:
let readFromJson(path: string) : 't list =
let convertToQr = File.ReadAllText(path)
Newtonsoft.Json.JsonConvert.DeserializeObject(convertToQr)
Here, the compiler knows that the generic argument of DeserializeObject must be 't list, because its result is being returned from readFromJson, and the result type of readFromJson is explicitly declared to be 't list. Similarly, just by noticing a generic type in the function definition, the compiler will infer that the function has one generic parameter.
In a similar way, you can let the compiler infer the required type when you call the function:
// call inferred to readFromJson<string>, because that's the required return type
let s: string list = readFromJson "/some/file.json"