In C# you can get the name of a method by using
nameof(ISomeClass.SomeMethod)
Is this doable in F#? When trying to dot into ISomeClass to get the SomeMethod, it merely says "SomeMethod is not a static method"
You can create a method based around F# quotations that retrieve an interface method in a type-safe manner.
open FSharp.Quotations
open FSharp.Quotations.Patterns
let getMethodName (e: Expr<'T -> 'U>) =
match e with
| Lambda (_, Call (_, mi, _)) -> mi.Name
| _ -> failwith "%A is not a valid getMethodName expression, expected Lamba(_ Call(_, _, _))"
type ISomeInterface =
interface
abstract SomeMethod: unit -> unit
end
[<EntryPoint>]
let main argv =
let name = <# fun (i : ISomeInterface) -> i.SomeMethod () #> |> getMethodName
printfn "%s" name
0
Related
This seems like a question that has an ultra simple answer, but I can't think of it:
Is there a built in method, within Result, for:
let (a: Result<'a, 'a>) = ...
match a with
| Ok x -> x
| Error e -> e
No, because this function requires the Ok type and the Error type to be the same, which makes Result less general.
No, there isn't any function which will allow you to do so. But you can easily define it:
[<RequireQualifiedAccess>]
module Result =
let join (value: Result<'a, 'a>) =
match value with
| Ok v -> v
| Error e -> e
let getResult s =
if System.String.IsNullOrEmpty s then
Error s
else
Ok s
let a =
getResult "asd"
|> Result.join
|> printfn "%s"
It doesn't make Result less general (as said by #brianberns), because it's not an instance member. Existence of Unwrap doesn't make Task less general
Update
After more scrupulous searching inside FSharpPlus and FSharpx.Extras I've found necessary function. It's signature ('a -> 'c) -> ('b -> 'c) -> Result<'a,'b> -> c instead of Result<'a, 'a> -> 'a and it's called Result.either in both libraries (source 1 and source 2). So in order to get value we may pass id as both parameters:
#r "nuget:FSharpPlus"
open FSharpPlus
// OR
#r "nuget:FSharpx.Extras"
open FSharpx
getResult "asd"
|> Result.either id id
|> printfn "%s"
Also it's may be useful to define shortcut and call it Result.join or Result.fromEither as it's called in Haskell
I'd like to transform my F# OOP version of Tagless Final into a typical FP approach and I'm thinking to use Statically Resolved Type Parameters of Type Classes from OO.
What I've done is
open System
open FSharpPlus
type UserName = string
type DataResult<'t> = DataResult of 't with
static member Map ( x:DataResult<'t> , f) =
match x with
| DataResult t -> DataResult (f t)
creating the SRTP I need
type Cache =
static member inline getOfCache cacheImpl data =
( ^T : (member getFromCache : 't -> DataResult<'t> option) (cacheImpl, data))
static member inline storeOfCache cacheImpl data =
( ^T : (member storeToCache : 't -> unit) (cacheImpl, data))
type DataSource() =
static member inline getOfSource dataSourceImpl data =
( ^T : (member getFromSource : 't -> DataResult<'t>) (dataSourceImpl, data))
static member inline storeOfSource dataSourceImpl data =
( ^T : (member storeToSource : 't -> unit) (dataSourceImpl, data))
and their concrete implementations
type CacheNotInCache() =
member this.getFromCache _ = None
member this.storeCache _ = ()
type CacheInCache() =
member this.getFromCache user = monad {
return! DataResult user |> Some}
member this.storeCache _ = ()
type DataSourceNotInCache() =
member this.getFromSource user = monad {
return! DataResult user }
type DataSourceInCache() =
member this.getFromSource _ =
raise (NotImplementedException())
by which I can define a tagless final DSL
let requestData (cacheImpl: ^Cache) (dataSourceImpl: ^DataSource) (userName:UserName) = monad {
match Cache.getOfCache cacheImpl userName with
| Some dataResult ->
return! map ((+) "cache: ") dataResult
| None ->
return! map ((+) "source: ") (DataSource.getOfSource dataSourceImpl userName) }
and that kind of works as follows
[<EntryPoint>]
let main argv =
let cacheImpl1 = CacheInCache()
let dataSourceImpl1 = DataSourceInCache()
let cacheImpl2 = CacheNotInCache()
let dataSourceImpl2 = DataSourceNotInCache()
requestData cacheImpl1 dataSourceImpl1 "john" |> printfn "%A"
//requestData (cacheImpl2 ) dataSourceImpl2 "john" |> printfn "%A"
0
The problem is that I'm getting the warning
construct causes code to be less generic than indicated by the type
annotations
for both cacheImpl1 and dataSourceImpl1 and so I can't reuse requestData for the other case.
Is there a way to detour this issue?
I'm not familiar with the abstraction you're trying to implement, but looking at your code it seems you're missing an inline modifier here:
let inline requestData (cacheImpl: ^Cache) (dataSourceImpl: ^DataSource) (userName:UserName) = monad {
match Cache.getOfCache cacheImpl userName with
| Some dataResult ->
return! map ((+) "cache: ") dataResult
| None ->
return! map ((+) "source: ") (DataSource.getOfSource dataSourceImpl userName) }
As a side note, you can simplify your map function like this:
type DataResult<'t> = DataResult of 't with
static member Map (DataResult t, f) = DataResult (f t)
I am familiar with final tagless, but I'm not sure why you would use SRTPs.
Final tagless uses type classes, and these can be emulated with interfaces (see the way scala emulates typeclasses).
The approach is similar to (basically the same) as "object algebra", which can be implemented using standard OO constructs.
I'm on a Mac running F# using .NET Core 2.0.
I have a function that looks like this:
let rec evaluate(x: string) =
match x with
// ... cases
| _ -> failwith "illogical"
I'd like to write an Expecto test that validates that the exception is thrown as expected, something along the lines of:
// doesn't compile
testCase "non-logic" <| fun _ ->
Expect.throws (evaluate "Kirkspeak") "illogical"
The error is
This expression was expected to have type
'unit -> unit' but here has type 'char'
unit -> unit makes me this is analogous to Assert.Fail, which is not what I want.
Being somewhat new to F# and Expecto, I'm having trouble locating a working example of asserting that an exception is thrown as expected. Does anyone have one?
Expect.throws has the signature (unit -> unit) -> string -> unit so the function you want to test must be (unit -> unit) or be wrapped inside a function that is (unit -> unit).
let rec evaluate (x: string) : char =
match x with
// ... cases
| _ -> failwith "illogical"
The compiler error is telling you that the function you passed to Expect.throws does not have the right signature yet.
[<Tests>]
let tests = testList "samples" [
test "non-logic" {
// (evaluate "Kirkspeak") is (string -> char)
// but expecto wants (unit -> unit)
Expect.throws (evaluate "Kirkspeak") "illogical"
}
]
[<EntryPoint>]
let main argv =
Tests.runTestsInAssembly defaultConfig argv
One way to make it work is to change
Expect.throws (evaluate "Kirkspeak") "illogical"
to
// you could instead do (fun () -> ...)
// but one use of _ as a parameter is for when you don't care about the argument
// the compiler will infer _ to be unit
Expect.throws (fun _ -> evaluate "Kirkspeak" |> ignore) "illogical"
Now expecto is happy!
This answer was the way I thought through it. It is usually helpful to follow the type signatures.
EDIT: I saw your error message saying This expression was expected to have type 'unit -> unit' but here has type 'char' so I updated my answer to match it.
In F#, we can create interface instance by object expression, but while I'm trying to use attribute ReflectedDefinition on the instance method, then I cannot get the quotations. The method info is declared in the interface type, not the instance type.
Here is my test code:
module Test
open System
open System.Reflection
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Quotations.Patterns
open Microsoft.FSharp.Quotations.DerivedPatterns
open Microsoft.FSharp.Quotations.ExprShape
type IMyInterface =
abstract Foo : int -> int
let createMyInterface () =
{ new IMyInterface with
[<ReflectedDefinition>]
member this.Foo a = a + 1 }
let expr =
let a = createMyInterface()
<# a.Foo(42) #>
let rec iterExpr (expr:Expr) =
match expr with
| Call(objectExpr, info, paramExprs) ->
printfn "info: %A" info
printfn "reflected type: %A" info.ReflectedType
match info with
| MethodWithReflectedDefinition methodExpr ->
printfn "%A" methodExpr
| _ -> failwith "No reflected definition"
| ShapeVar _ -> failwithf "TODO: %A" expr
| ShapeLambda _ -> failwithf "TODO: %A" expr
| ShapeCombination _ -> failwithf "TODO: %A" expr
let test() =
iterExpr expr
[<EntryPoint>]
let main argv =
test()
0 // return an integer exit code
If I run it, I got exception:
C:\Users\Xiang\Documents\Inbox\TTTT\bin\Debug>TTTT
info: Int32 Foo(Int32)
reflected type: Test+IMyInterface
Unhandled Exception: System.Exception: No reflected definition
at Microsoft.FSharp.Core.Operators.FailWith[T](String message)
at Test.iterExpr(FSharpExpr expr) in C:\Users\Xiang\Documents\Inbox\TTTT\Program.fs:line 30
at Test.test() in C:\Users\Xiang\Documents\Inbox\TTTT\Program.fs:line 37
at Test.main(String[] argv) in C:\Users\Xiang\Documents\Inbox\TTTT\Program.fs:line 41
And I also checked the generated assembly with dotPeek, it is implemented as a derived class:
[CompilationMapping(SourceConstructFlags.ObjectType)]
[Serializable]
public interface IMyInterface
{
int Foo([In] int obj0);
}
[CompilationMapping(SourceConstructFlags.Closure)]
[Serializable]
[SpecialName]
[StructLayout(LayoutKind.Auto, CharSet = CharSet.Auto)]
internal sealed class createMyInterface\u004014 : Test.IMyInterface
{
public createMyInterface\u004014()
{
base.\u002Ector();
Test.createMyInterface\u004014 createMyInterface14 = this;
}
[ReflectedDefinition]
int Test.IMyInterface.Test\u002DIMyInterface\u002DFoo([In] int obj0)
{
return obj0 + 1;
}
}
So, the problem is, when I call the Foo method in quotation, the Call pattern get MethodInfo which is declared at interface type, which has no definition. So how could I get the actually implementation MethodInfo? and then I can get the quotation of the implementation?
Here's your problem in a nutshell:
You're calling a virtual method through an instance of the type where the method is defined.
You want the quotation to contain a call to the method as defined on the derived class.
This won't work, and isn't limited to interfaces or object expressions:
type A() =
abstract M : unit -> unit
default this.M() = printfn "abstract"
type T() =
inherit A() with
[<ReflectedDefinition>]
override this.M() = printfn "override"
let expr =
let a : A = upcast T()
<# a.M() #>
Fundamentally, the whole point of an object expression is to provide an anonymous implementation of a non-sealed class, so what you're asking for doesn't make sense to me - the compiler only knows that the object is some instance implementing that interface but can't know the concrete type of the instance and therefore can't know which (of potentially many) concrete method to use.
I continue to work on a printer for F# quoted expressions, it doesn't have to be perfect, but I'd like to see what is possible. The active patterns in Microsoft.FSharp.Quotations.Patterns and Microsoft.FSharp.Quotations.DerivedPatterns used for decomposing quoted expressions will typically provide MemberInfo instances when appropriate, these can be used to obtain the name of a property, function, etc. and their "declaring" type, such as a module or static class. The problem is, I only know how to obtain the CompiledName from these instances but I'd like the F# name. For example,
> <# List.mapi (fun i j -> i+j) [1;2;3] #> |> (function Call(_,mi,_) -> mi.DeclaringType.Name, mi.Name);;
val it : string * string = ("ListModule", "MapIndexed")
How can this match be rewritten to return ("List", "mapi")? Is it possible?
FYI, here is my final polished solution from Stringer Bell and pblasucci's help:
let moduleSourceName (declaringType:Type) =
FSharpEntity.FromType(declaringType).DisplayName
let methodSourceName (mi:MemberInfo) =
mi.GetCustomAttributes(true)
|> Array.tryPick
(function
| :? CompilationSourceNameAttribute as csna -> Some(csna)
| _ -> None)
|> (function | Some(csna) -> csna.SourceName | None -> mi.Name)
//usage:
let sourceNames =
<# List.mapi (fun i j -> i+j) [1;2;3] #>
|> (function Call(_,mi,_) -> mi.DeclaringType |> moduleSourceName, mi |> methodSourceName);
You can use F# powerpack for that purpose:
open Microsoft.FSharp.Metadata
...
| Call(_, mi, _) ->
let ty = Microsoft.FSharp.Metadata.FSharpEntity.FromType(mi.DeclaringType)
let name = ty.DisplayName // name is List
However, I don't think if it's possible to retrieve function name with powerpack.
Edit:
As hinted by pblasucci, you can use CompilationSourceName attribute for retrieving source name:
let infos = mi.DeclaringType.GetMember(mi.Name)
let att = infos.[0].GetCustomAttributes(true)
let fName =
(att.[1] :?> CompilationSourceNameAttribute).SourceName // fName is mapi