open System.Collections.Concurrent
let rec mkPrinter<'T> () : 'T -> string =
let wrap(p : 'a -> string) = unbox<'T -> string> p
let mkMemberPrinter (shape : IShapeMember<'DeclaringType>) =
shape.Accept { new IMemberVisitor<'DeclaringType, 'DeclaringType -> string> with
member __.Visit (shape : ShapeMember<'DeclaringType, 'Field>) =
let fieldPrinter = mkPrinter<'Field>()
fieldPrinter << shape.Get }
let mkFieldPrinter (shape : IShapeReadOnlyMember<'DeclaringType>) =
shape.Accept { new IReadOnlyMemberVisitor<'DeclaringType, list<string * ('DeclaringType -> string)>> with
member __.Visit (shape : ReadOnlyMember<'DeclaringType, 'Field2>) =
let fieldPrinter = mkPrinter<'Field2>()
[ shape.MemberInfo.Name, fieldPrinter << shape.Get ]
| Shape.Unit -> wrap(fun () -> "()")
| Shape.Bool -> wrap(sprintf "%b")
| Shape.Byte -> wrap(fun (b:byte) -> sprintf "%duy" b)
| Shape.Int32 -> wrap(sprintf "%d")
| Shape.Int64 -> wrap(fun (b:int64) -> sprintf "%dL" b)
| Shape.String -> wrap(sprintf "\"%s\"")
| Shape.Double -> wrap(sprintf "%f")
| Shape.FSharpOption s ->
new ITypeVisitor<'T -> string> with
wrap(function None -> "None" | Some t -> sprintf "Some (%s)" (tp t))
new ITypeVisitor<'T -> string> with
wrap(fun ts -> ts |> List.map tp |> String.concat "; " |> sprintf "[%s]")
| Shape.Array s when s.Rank = 1 ->
new ITypeVisitor<'T -> string> with
let tp = mkPrinter<'a> ()
wrap(fun ts -> ts |> Array.map tp |> String.concat "; " |> sprintf "[|%s|]")
new IFSharpSetVisitor<'T -> string> with
member __.Visit<'a when 'a : comparison> () =
wrap(fun (s:Set<'a>) -> s |> Seq.map tp |> String.concat "; " |> sprintf "set [%s]")
| Shape.FSharpUnion (:? ShapeFSharpUnion<'T> as shape) ->
let cases : ShapeFSharpUnionCase<'T> [] = shape.UnionCases
let mkUnionCasePrinter (case : ShapeFSharpUnionCase<'T>) =
let fieldPrinters = case.Fields |> Array.map mkMemberPrinter
|> Seq.map (fun fp -> fp u)
|> sprintf "%s(%s)" case.CaseInfo.Name
let casePrinters = cases |> Array.map mkUnionCasePrinter
let tag : int = shape.GetTag u
| Shape.Poco (:? ShapePoco<'T> as shape) ->
let propPrinters = shape.Properties |> Array.map mkFieldPrinter
|> Seq.map (fun (label, ep) -> let value = ep r in sprintf "%s = %s" label value)
| _ -> failwithf "unsupported type '%O'" typeof<'T>
[<StructuredFormatDisplay("{AsString}")>]
let mutable balance = 0.0
let mutable firstName = ""
let mutable lastName = ""
member this.AccountNumber
and set(value) = number <- value
and set(value) = firstName <- value
and set(value) = lastName <- value
and set(value) = balance <- value
member this.Deposit(amount: float) = this.Balance <- this.Balance + amount
member this.Withdraw(amount: float) = this.Balance <- this.Balance - amount
override this.ToString() = this |> mkPrinter()
member private this.AsString = this |> mkPrinter()
[<StructuredFormatDisplay("{AsString}")>]
with member private this.AsString = this |> mkPrinter()
Account() |> printfn "%A"
OneOption |> printfn "%A"