Why isn't a tuple parameter being recognized on my function?
I have the following function:
let deposit depositType ((logTransaction:string -> string -> unit), (file:string)) =
depositType |> makeInitialDeposit
|> sprintf "Deposited: %f"
|> logTransaction file
Note how the last argument of the function is a tuple:
((logTransaction:string -> string -> unit), (file:string))
I then attempt to invoke this function using the following:
let file = "c:\\myfile.txt"
(writeToFile, file) ||> deposit OneDollarBill
Yet, it's stating that it's not expecting a tuple. Instead, it's expecting:
Expecting a (string -> string -> unit) -> string -> 'a
The complete error is here:
Type mismatch. Expecting a
(string -> string -> unit) -> string -> 'a but given a
(string -> string -> unit) * string -> unit The type 'string -> string -> unit' does not match the type '(string -> string -> unit) * string'
Here's the code:
let writeToFile (filePath:string) (message:string) =
let file = new System.IO.StreamWriter(filePath)
file.WriteLine(message)
file.Close()
let makeInitialDeposit deposit =
deposit |> insert []
let deposit depositType ((logTransaction:string -> string -> unit), (file:string)) =
depositType |> makeInitialDeposit
|> sprintf "Deposited: %f"
|> logTransaction file
let file = "c:\\myfile.txt"
(writeToFile, file) ||> deposit OneDollarBill
||> unpacks a tuple 'a * 'b to call a normal function 'a -> 'b -> 'c; as shown, you don't want this unpacking behavior, as you have 'a * 'b -> 'c.
Either change ||> to |> so the tuple is passed directly:
(writeToFile, file) |> deposit OneDollarBill
Or change deposit to accept curried arguments rather than a tuple:
let deposit depositType (logTransaction:string -> string -> unit) (file:string) =
...
(writeToFile, file) ||> deposit OneDollarBill
Related
How can I print argument function name that was used to call this function?
open System
open System.Threading.Tasks
let logger (f: ('a -> Task<'b>)) : ('a -> Task<'b>) =
printfn "Hey: %O" (nameof f) // I would like to print "myFunc", not "f"
f
let myFunc x = task {return x }
let d = (logger myFunc) 3
You could use the ReflectedDefinition(true) attribute, which automatically quotes the argument of a method call and gives you both the value (to use at runtime) and the code quotation from which you can (if the format is right) extract the name. This only seems to work with method calls though:
type Logger =
static member log([<ReflectedDefinition(true)>]f: Expr<('a -> Task<'b>)>) : ('a -> Task<'b>) =
match f with
| Patterns.WithValue(v, _, Patterns.Lambda(_, Patterns.Call(_, mi, _))) ->
printfn "Hello %s!" mi.Name
unbox v
| _ -> failwith "Wrong format"
let myFunc x = task {return x }
let d = (Logger.log myFunc) 3
The design and motivation of this is discussed in the F# 4.0 Speclet: Auto-Quotation of Arguments at Method Calls
Please explain the following function signature which appeared when I hovered over the function in VS Code. I'm especially curious what exactly "requires" means and why 'b is 'a.
val handleSingleEvent:
: Request
-> 'b (requires :> seq<list<string>>)
Generic Parameters
'b is 'a
Below is the code
let handleEvents (requests: Request list, reqEventQueue: EventQueue, session: Session) =
let rec handleSingleEvent (request: Request) : seq<list<string>> =
seq {
let eventObj = reqEventQueue.NextEvent()
match eventObj.Type with
| Event.EventType.REQUEST_STATUS -> yield processMiscEvents eventObj |> makeJson
| Event.EventType.ADMIN -> yield processAdminEvent eventObj |> makeJson
| Event.EventType.AUTHORIZATION_STATUS -> yield processAuthEvent eventObj session |> makeJson
| Event.EventType.PARTIAL_RESPONSE ->
yield processReferenceResponseEvent eventObj
|> makeJson
yield! handleSingleEvent request
| Event.EventType.RESPONSE -> yield processReferenceResponseEvent eventObj |> makeJson
| _ -> yield processMiscEvents eventObj |> makeJson
} |> ignore
handleSingleEvent request
List.map (fun request -> handleSingleEvent request) requests
After adding the return type annotation seq<list<string>>, hovering over the function in VS Code now displays the function signature as
val handleSingleEvent:
: Request
-> seq<list<string>>
"requires" disappeared and "Generic Parameters `b is `a" disappeared.
'requires' indicates a member constraint, meaning that the generic type argument is constrained to exhibit such member. As a brief example:
let inline f<'b when 'b : (member Name : string)> (x: 'b) = x
The generic type 'b is now constrained to have a member Name that returns a string.
https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/generics/constraints
When I'm working in the F# REPL fsharpi whenever I enter a new function the signature is printed after I've entered them:
> let foo x = x;;
val foo : x:'a -> 'a
Is there a way to retrieve this as a string? The reason I'm asking is that I'm using IfSharp for Jupyter notebooks which doesn't display the signatures, but I'd like to be able to show the types of functions for demonstration purposes.
I've messed around a bit but can't get anything useful, I've tried:
let foo x = (x, x)
printfn "%A" (foo.GetType())
printfn "%A" foo
But this isn't quite what I need:
FSI_0013+clo#3-1
<fun:it#5-2>
Is it possible to access this at all?
AFAIK, there's no function in FSharp.Core for getting a type's string representation as it would appear to the compiler (though maybe there's something in FSharp.Compiler.Services -- I haven't checked). Here's a small function that works for most simple uses:
open System
let (|TFunc|_|) (typ: Type) =
if typ.IsGenericType && typ.GetGenericTypeDefinition () = typeof<int->int>.GetGenericTypeDefinition () then
match typ.GetGenericArguments() with
| [|targ1; targ2|] -> Some (targ1, targ2)
| _ -> None
else
None
let rec typeStr (typ: Type) =
match typ with
| TFunc (TFunc(_, _) as tfunc, t) -> sprintf "(%s) -> %s" (typeStr tfunc) (typeStr t)
| TFunc (t1, t2) -> sprintf "%s -> %s" (typeStr t1) (typeStr t2)
| typ when typ = typeof<int> -> "int"
| typ when typ = typeof<string> -> "string"
| typ when typ.IsGenericParameter -> sprintf "'%s" (string typ)
| typ -> string typ
typeStr typeof<(string -> (string -> int) -> int) -> int>
// val it: string = "string -> (string -> int) -> int"
typeStr (typeof<int->int>.GetGenericTypeDefinition())
// val it: string = "'T -> 'TResult"
You can easily write a function on top of this to use typeStr on a value's type:
let valTypeString x = typStr (x.GetType ())
You can analyze types representing F# functions, with the help of the Microsoft.FSharp.Reflection namespace. There is the caveat that generic function arguments default to System.Object, and that other F# types which may form incomplete patterns (e.g. union cases, records) are not included.
open Microsoft.FSharp.Reflection
let funString o =
let rec loop nested t =
if FSharpType.IsTuple t then
FSharpType.GetTupleElements t
|> Array.map (loop true)
|> String.concat " * "
elif FSharpType.IsFunction t then
let fs = if nested then sprintf "(%s -> %s)" else sprintf "%s -> %s"
let domain, range = FSharpType.GetFunctionElements t
fs (loop true domain) (loop false range)
else
t.FullName
loop false (o.GetType())
let foo x = x
funString foo
// val it : string = "System.Object -> System.Object"
I have the function to map a function to "Reader-Result", where f is 'a->'b:
('a->'b) -> Reader<Result<'a,'c>> -> Reader<Result<'b,'c>>
let map f = Reader.map <| Result.map f
But how to I write a similar map that takes the function 'a->Result<'b,'c> as input?
The function that's analogous to map, but whose argument returns a Result<_,_>, is called bind. Its signature is:
bind : ('a -> Result<'b, 'c>) -> Result<'a, 'c> -> Result<'b, 'c>
I am assuming that the signature you want is:
yourFunction : ('a -> Result<'b, 'c>) -> Reader<Result<'a, 'c>> -> Reader<Result<'b, 'c>>
To obtain such function, combine Result.bind with Reader.map:
yourFunction f = Reader.map <| Result.bind f
How to fix the code? Is the inline/Statically Resolved Type the same powerful as structural typing?
The type 'XmlProvider<...>.Parameter' does not support the operator 'get_Value'?
let input1 = """<r1><parameters><parameter name="token">1</parameter><parameter name="other">xxx</parameter></parameters><othersOf1>..sample....</othersOf1></r1>"""
let xml1 = XmlProvider<"""<r1><parameters><parameter name="token">1</parameter><parameter name="other">xxx</parameter></parameters><othersOf1>...</othersOf1></r1>""">.Parse(input1)
let inline get name parameters =
parameters |> Seq.tryFind (fun x -> (^P : (member Name : 'a) x) = name)
|> Option.map (fun v -> (^P : (member Value : 'b) v))
get "token" xml1.Parameters
Value is only defined for nodes that have a single type (or types the type provider can unify, e.g. 2 and 3.0). In your example the second value is the string xxx, so a parameter gets two properties: Number and String, each returning an option of the respective type. You can either
change your input to have one single consistent value type (xxx → 2)
let xml1 = XmlProvider<"""<r1><parameters><parameter name="token">1</parameter><parameter name="other">2</parameter></parameters><othersOf1>...</othersOf1></r1>""">.Parse(input1)
turn them into a single output type (e.g. string)
let inline get name parameters =
parameters |> Seq.tryFind (fun x -> (^P : (member Name : 'a) x) = name)
|> Option.bind (fun v ->
match (^P : (member Number : int option) v) with
| Some number -> Some (string number)
| None -> (^P : (member String : string option) v))
create an appropriate DU
type Value = Number of int | Name of string
let inline get name parameters =
parameters |> Seq.tryFind (fun x -> (^P : (member Name : 'a) x) = name)
|> Option.map (fun v ->
match (^P : (member Number : int option) v) with
| Some number -> Number number
| None ->
match (^P : (member String : string option) v) with
| Some s -> Name s
| _ -> failwith "Either number or string should be Some(value)")
if you don't know the values upfront, you can also tell the type provider to not infer them at all:
XmlProvider<"""...""", InferTypesFromValues=false>
this will cause parameters to have a Value : string property.