1 people like it.
Like the snippet!
Just because
It's probably not possible, but I'm going to see how far I can get...
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
|
open System.Reflection
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter
open Microsoft.FSharp.Reflection
type TestRecord =
{
AnInt : int
AString : string
}
let propToGetLens<'a> _ (prop : PropertyInfo) =
let recordVar = Var("record", typeof<'a>)
let record = Expr.Var(recordVar)
let getMethodInfo = prop.GetGetMethod()
let get = Expr.Call(record, getMethodInfo, [])
Expr.Lambda(recordVar, get)
let propToSetLens<'a> index (prop : PropertyInfo) =
let recordType = typeof<'a>
let recordVar = Var("record", typeof<'a>)
let record = Expr.Coerce(Expr.Var(recordVar), typeof<obj>)
let valueVar = Var("value", prop.PropertyType)
let value = Expr.Coerce(Expr.Var(valueVar), typeof<obj>)
let newRecord =
<@
let values =
FSharpValue.GetRecordFields((%%record : obj))
|> List.ofArray
|> List.mapi (fun i v ->
if i = index then
(%%value:obj)
else v)
|> Array.ofList
FSharpValue.MakeRecord((%%record).GetType(), values)
@>
Expr.Lambda(valueVar, Expr.Lambda(recordVar, Expr.Coerce(newRecord, recordType)))
let MakeLenses<'a> () =
let recordType = typeof<'a>
if not <| FSharpType.IsRecord recordType then failwith "I'm not a record"
let fields =
FSharpType.GetRecordFields recordType
|> List.ofArray
fields
|> List.mapi (fun i f -> <@ (%%(Expr.Coerce(propToGetLens<'a> i f, typeof<obj>)):obj), (%%(Expr.Coerce(propToSetLens<'a> i f, typeof<obj>)):obj) @>)
let lenses =
MakeLenses<TestRecord>()
|> List.head
|> EvaluateQuotation
:?> obj * obj
let getLens, setLens =
fst lenses :?> TestRecord -> int, snd lenses :?> int -> TestRecord -> TestRecord
printfn "%A" (getLens, setLens)
printfn "Get: %A" <| getLens { AnInt = 22; AString = "" }
// Get: 22
printfn "Set: %A" <| getLens (setLens 50 { AnInt = 10; AString = "" })
// Set: 50
System.Console.ReadLine() |> ignore
|
namespace System
namespace System.Reflection
namespace Microsoft
namespace Microsoft.FSharp
namespace Microsoft.FSharp.Quotations
namespace Microsoft.FSharp.Linq
namespace Microsoft.FSharp.Linq.RuntimeHelpers
module LeafExpressionConverter
from Microsoft.FSharp.Linq.RuntimeHelpers
namespace Microsoft.FSharp.Reflection
type TestRecord =
{AnInt: int;
AString: string;}
Full name: Script.TestRecord
TestRecord.AnInt: int
Multiple items
val int : value:'T -> int (requires member op_Explicit)
Full name: Microsoft.FSharp.Core.Operators.int
--------------------
type int = int32
Full name: Microsoft.FSharp.Core.int
--------------------
type int<'Measure> = int
Full name: Microsoft.FSharp.Core.int<_>
TestRecord.AString: string
Multiple items
val string : value:'T -> string
Full name: Microsoft.FSharp.Core.Operators.string
--------------------
type string = System.String
Full name: Microsoft.FSharp.Core.string
val propToGetLens<'a> : int -> prop:PropertyInfo -> Expr
Full name: Script.propToGetLens
val prop : PropertyInfo
type PropertyInfo =
inherit MemberInfo
member Attributes : PropertyAttributes
member CanRead : bool
member CanWrite : bool
member Equals : obj:obj -> bool
member GetAccessors : unit -> MethodInfo[] + 1 overload
member GetConstantValue : unit -> obj
member GetGetMethod : unit -> MethodInfo + 1 overload
member GetHashCode : unit -> int
member GetIndexParameters : unit -> ParameterInfo[]
member GetOptionalCustomModifiers : unit -> Type[]
...
Full name: System.Reflection.PropertyInfo
val recordVar : Var
Multiple items
type Var =
interface IComparable
new : name:string * typ:Type * ?isMutable:bool -> Var
member IsMutable : bool
member Name : string
member Type : Type
static member Global : name:string * typ:Type -> Var
Full name: Microsoft.FSharp.Quotations.Var
--------------------
new : name:string * typ:System.Type * ?isMutable:bool -> Var
val typeof<'T> : System.Type
Full name: Microsoft.FSharp.Core.Operators.typeof
val record : Expr
Multiple items
type Expr =
override Equals : obj:obj -> bool
member GetFreeVars : unit -> seq<Var>
member Substitute : substitution:(Var -> Expr option) -> Expr
member ToString : full:bool -> string
member CustomAttributes : Expr list
member Type : Type
static member AddressOf : target:Expr -> Expr
static member AddressSet : target:Expr * value:Expr -> Expr
static member Application : functionExpr:Expr * argument:Expr -> Expr
static member Applications : functionExpr:Expr * arguments:Expr list list -> Expr
...
Full name: Microsoft.FSharp.Quotations.Expr
--------------------
type Expr<'T> =
inherit Expr
member Raw : Expr
Full name: Microsoft.FSharp.Quotations.Expr<_>
static member Expr.Var : variable:Var -> Expr
val getMethodInfo : MethodInfo
PropertyInfo.GetGetMethod() : MethodInfo
PropertyInfo.GetGetMethod(nonPublic: bool) : MethodInfo
val get : Expr
static member Expr.Call : methodInfo:MethodInfo * arguments:Expr list -> Expr
static member Expr.Call : obj:Expr * methodInfo:MethodInfo * arguments:Expr list -> Expr
static member Expr.Lambda : parameter:Var * body:Expr -> Expr
val propToSetLens<'a> : index:int -> prop:PropertyInfo -> Expr
Full name: Script.propToSetLens
val index : int
val recordType : System.Type
static member Expr.Coerce : source:Expr * target:System.Type -> Expr
type obj = System.Object
Full name: Microsoft.FSharp.Core.obj
val valueVar : Var
property PropertyInfo.PropertyType: System.Type
val value : Expr
val newRecord : Expr<obj>
val values : obj []
type FSharpValue =
static member GetExceptionFields : exn:obj * ?bindingFlags:BindingFlags -> obj []
static member GetRecordField : record:obj * info:PropertyInfo -> obj
static member GetRecordFields : record:obj * ?bindingFlags:BindingFlags -> obj []
static member GetTupleField : tuple:obj * index:int -> obj
static member GetTupleFields : tuple:obj -> obj []
static member GetUnionFields : value:obj * unionType:Type * ?bindingFlags:BindingFlags -> UnionCaseInfo * obj []
static member MakeFunction : functionType:Type * implementation:(obj -> obj) -> obj
static member MakeRecord : recordType:Type * values:obj [] * ?bindingFlags:BindingFlags -> obj
static member MakeTuple : tupleElements:obj [] * tupleType:Type -> obj
static member MakeUnion : unionCase:UnionCaseInfo * args:obj [] * ?bindingFlags:BindingFlags -> obj
...
Full name: Microsoft.FSharp.Reflection.FSharpValue
static member FSharpValue.GetRecordFields : record:obj * ?allowAccessToPrivateRepresentation:bool -> obj []
static member FSharpValue.GetRecordFields : record:obj * ?bindingFlags:BindingFlags -> obj []
Multiple items
module List
from Microsoft.FSharp.Collections
--------------------
type List<'T> =
| ( [] )
| ( :: ) of Head: 'T * Tail: 'T list
interface IEnumerable
interface IEnumerable<'T>
member Head : 'T
member IsEmpty : bool
member Item : index:int -> 'T with get
member Length : int
member Tail : 'T list
static member Cons : head:'T * tail:'T list -> 'T list
static member Empty : 'T list
Full name: Microsoft.FSharp.Collections.List<_>
val ofArray : array:'T [] -> 'T list
Full name: Microsoft.FSharp.Collections.List.ofArray
val mapi : mapping:(int -> 'T -> 'U) -> list:'T list -> 'U list
Full name: Microsoft.FSharp.Collections.List.mapi
val i : int
val v : obj
module Array
from Microsoft.FSharp.Collections
val ofList : list:'T list -> 'T []
Full name: Microsoft.FSharp.Collections.Array.ofList
static member FSharpValue.MakeRecord : recordType:System.Type * values:obj [] * ?allowAccessToPrivateRepresentation:bool -> obj
static member FSharpValue.MakeRecord : recordType:System.Type * values:obj [] * ?bindingFlags:BindingFlags -> obj
val MakeLenses<'a> : unit -> Expr<obj * obj> list
Full name: Script.MakeLenses
val not : value:bool -> bool
Full name: Microsoft.FSharp.Core.Operators.not
type FSharpType =
static member GetExceptionFields : exceptionType:Type * ?bindingFlags:BindingFlags -> PropertyInfo []
static member GetFunctionElements : functionType:Type -> Type * Type
static member GetRecordFields : recordType:Type * ?bindingFlags:BindingFlags -> PropertyInfo []
static member GetTupleElements : tupleType:Type -> Type []
static member GetUnionCases : unionType:Type * ?bindingFlags:BindingFlags -> UnionCaseInfo []
static member IsExceptionRepresentation : exceptionType:Type * ?bindingFlags:BindingFlags -> bool
static member IsFunction : typ:Type -> bool
static member IsModule : typ:Type -> bool
static member IsRecord : typ:Type * ?bindingFlags:BindingFlags -> bool
static member IsTuple : typ:Type -> bool
...
Full name: Microsoft.FSharp.Reflection.FSharpType
static member FSharpType.IsRecord : typ:System.Type * ?allowAccessToPrivateRepresentation:bool -> bool
static member FSharpType.IsRecord : typ:System.Type * ?bindingFlags:BindingFlags -> bool
val failwith : message:string -> 'T
Full name: Microsoft.FSharp.Core.Operators.failwith
val fields : PropertyInfo list
static member FSharpType.GetRecordFields : recordType:System.Type * ?allowAccessToPrivateRepresentation:bool -> PropertyInfo []
static member FSharpType.GetRecordFields : recordType:System.Type * ?bindingFlags:BindingFlags -> PropertyInfo []
val f : PropertyInfo
val lenses : obj * obj
Full name: Script.lenses
val head : list:'T list -> 'T
Full name: Microsoft.FSharp.Collections.List.head
val EvaluateQuotation : Expr -> obj
Full name: Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.EvaluateQuotation
val getLens : (TestRecord -> int)
Full name: Script.getLens
val setLens : (int -> TestRecord -> TestRecord)
Full name: Script.setLens
val fst : tuple:('T1 * 'T2) -> 'T1
Full name: Microsoft.FSharp.Core.Operators.fst
val snd : tuple:('T1 * 'T2) -> 'T2
Full name: Microsoft.FSharp.Core.Operators.snd
val printfn : format:Printf.TextWriterFormat<'T> -> 'T
Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
type Console =
static member BackgroundColor : ConsoleColor with get, set
static member Beep : unit -> unit + 1 overload
static member BufferHeight : int with get, set
static member BufferWidth : int with get, set
static member CapsLock : bool
static member Clear : unit -> unit
static member CursorLeft : int with get, set
static member CursorSize : int with get, set
static member CursorTop : int with get, set
static member CursorVisible : bool with get, set
...
Full name: System.Console
System.Console.ReadLine() : string
val ignore : value:'T -> unit
Full name: Microsoft.FSharp.Core.Operators.ignore
More information