F#: Attributes on discriminated union fields? - reflection

I can do this:
type AttrAttribute () =
inherit Attribute ()
type MyDU =
| [<Attr>]A of bool
| [<Attr>]B of int * string
| [<Attr>]C of byte * char * int64
... but is there any way to do this?
type MyDU =
| A of [<Attr>]bool
| B of int * [<Attr>]string
| C of [<Attr>]byte * char * [<Attr>]int64
Apparently, the case values are just fields (e.g. let v = B (13, "oops") in (Microsoft.FSharp.Reflection.FSharpValue.GetUnionFields (v, v.GetType ()) |> fst).GetFields ()), so I'm hoping this is doable, somehow.

This is quite contrived:
type A_ = { [<Attr>] Item1 : int }
type B_ = { [<Attr>] Item1 : int; [<Attr>] Item2 : string }
type MyDU =
| A of A_
| B of B_
And
let v = A({Item1 = 1})
let record = ((FSharpValue.GetUnionFields (v, v.GetType ()) |> fst).GetFields ()) |> Array.head
let attrs = record.PropertyType.GetProperties() |> Array.collect(fun p -> p.GetCustomAttributes(false))

Related

Recursively unpack list into elements

I have a list and would like to return each element from it individually. Basically like popping from a stack. For example:
let rnd = new System.Random()
let rnds = List.init 10 (fun _ -> rnd.Next(100))
List.iter (fun x -> printfn "%A"x ) rnds
However instead of iterating, I would actually like to return each integer one after the other until the list is empty. So basically something along the lines of:
List.head(rnds)
List.head(List.tail(rnds))
List.head(List.tail(List.tail(rnds)))
List.head(List.tail(List.tail(List.tail(List.tail(rnds)))))
Unfortunately my attempts at a recursive solution or even better something using fold or scan were unsuccessful. For example this just returns the list (same as map).
let pop3 (rnds:int list) =
let rec pop3' rnds acc =
match rnds with
| head :: tail -> List.tail(tail)
| [] -> acc
pop3' [] rnds
Would uncons do what you need?
let uncons = function h::t -> Some (h, t) | [] -> None
You can use it to 'pop' the head of a list:
> rnds |> uncons;;
val it : (int * int list) option =
Some (66, [17; 93; 33; 17; 21; 1; 49; 5; 96])
You can repeat this:
> rnds |> uncons |> Option.bind (snd >> uncons);;
val it : (int * int list) option = Some (17, [93; 33; 17; 21; 1; 49; 5; 96])
> rnds |> uncons |> Option.bind (snd >> uncons) |> Option.bind (snd >> uncons);;
val it : (int * int list) option = Some (93, [33; 17; 21; 1; 49; 5; 96])
This seems like a good oppurtunity for a class
type unpacker(l) =
let mutable li = l
member x.get() =
match li with
|h::t -> li<-t;h
|_ -> failwith "nothing left to return"

Propositional Logic Valuation in SML

I'm trying to define a propositional logic valuation using SML structure. A valuation in propositional logic maps named variables (i.e., strings) to Boolean values.
Here is my signature:
signature VALUATION =
sig
type T
val empty: T
val set: T -> string -> bool -> T
val value_of: T -> string -> bool
val variables: T -> string list
val print: T -> unit
end;
Then I defined a matching structure:
structure Valuation :> VALUATION =
struct
type T = (string * bool) list
val empty = []
fun set C a b = (a, b) :: C
fun value_of [] x = false
| value_of ((a,b)::d) x = if x = a then b else value_of d x
fun variables [] = []
| variables ((a,b)::d) = a::(variables d )
fun print valuation =
(
List.app
(fn name => TextIO.print (name ^ " = " ^ Bool.toString (value_of valuation name) ^ "\n"))
(variables valuation);
TextIO.print "\n"
)
end;
So the valuations should look like [("s",true), ("c", false), ("a", false)]
But I can't declare like a structure valuation or make an instruction like: [("s",true)]: Valuation.T; When I tried to use the valuation in a function, I get errors like:
Can't unify (string * bool) list (*In Basis*) with
Valuation.T
Could someone help me? Thanks.
The type Valuation.T is opaque (hidden).
All you know about it is that it's called "T".
You can't do anything with it except through the VALUATION signature, and that signature makes no mention of lists.
You can only build Valuations using the constructors empty and set, and you must start with empty.
- val e = Valuation.empty;
val e = - : Valuation.T
- val v = Valuation.set e "x" true;
val v = - : Valuation.T
- val v2 = Valuation.set v "y" false;
val v2 = - : Valuation.T
- Valuation.value_of v2 "x";
val it = true : bool
- Valuation.variables v2;
val it = ["y","x"] : string list
- Valuation.print v2;
y = false
x = true
val it = () : unit
Note that every Valuation.T value is printed as "-" since the internal representation isn't exposed.

SML: Determining Type of Function

Suppose all I know about a function is that it is of type:
int list -> int * string -> int
Is there any way of knowing in advance whether this means:
(int list -> int * string) -> int or int list -> (int * string -> int)?
Thanks,
bclayman
-> is right associative in SML type annotations, so int list -> (int * string -> int) is correct.
Consider this simple experiment in the REPL:
- fun add x y = x+y;
val add = fn : int -> int -> int
add is a function which, when fed an int, returns a function, namely the function which sends y to x + y -- hence its type is int -> (int ->int). It isn't a function which, when a fed a function from ints to ints outputs an int (which is what (int -> int) -> int would be). A somewhat artificial example of the later sort of thing is:
- fun apply_to_zero_and_increment f = 1 + f(0);
val apply_to_zero_and_increment = fn : (int -> int) -> int
If I define fun g(x) = x + 5 then apply_to_zero_and_increment g returns 6.

Pattern match against existing variables

I have a structure of nested maps:
[<RequireQualifiedAccess>]
type NestedMap =
| Object of Map<string,NestedMap>
| Value of int
I need to prune the structure.
The purpose of the code is to maintain intact the nested structure of the maps and of the map where the key value pair is found, pruning the branches where the key value pair is not found.
Here is the test NestedMap:
let l2' = NestedMap.Object ( List.zip ["C"; "S"; "D"] [NestedMap.Value(10); NestedMap.Value(20); NestedMap.Value(30)] |> Map.ofList)
let l3 = NestedMap.Object ( List.zip ["E"; "S"; "F"] [NestedMap.Value(100); NestedMap.Value(200); NestedMap.Value(300)] |> Map.ofList)
let l2'' = NestedMap.Object ( List.zip ["G"; "H"; "I"; "S"] [NestedMap.Value(30); l3; NestedMap.Value(40); NestedMap.Value(50)] |> Map.ofList)
let l1 = NestedMap.Object ( List.zip ["Y"; "A"; "B"] [NestedMap.Value(1); l2'; l2''] |> Map.ofList)
This is my code:
let rec pruneWithKeyValue (keyvalue: string * int) (json: NestedMap) =
let condition ck cv =
let tgtKey = (fst keyvalue)
let tgtVal = (snd keyvalue)
match (ck, cv) with
| (tgtKey, NestedMap.Value(tgtVal)) ->
printfn ">>> Found match : "
printfn " ck = %s " ck
printfn " tgtKey and tgtVal == %s, %i" tgtKey tgtVal
true
| _ -> false
match json with
| NestedMap.Object nmap ->
if (nmap |> Map.exists (fun k v -> condition k v)) then
json
else
printfn "Expanding w keyvalue: (%s,%i): " (fst keyvalue) (snd keyvalue)
let expanded = nmap |> Map.map (fun k v -> pruneWithKeyValue keyvalue v)
NestedMap.Object(expanded |> Map.filter (fun k v -> v <> NestedMap.Object (Map.empty)))
| _ -> NestedMap.Object (Map.empty)
let pruned = pruneWithKeyValue ("S",20) l1
let res = (pruned = l1)
The result is not what desired:
>>> Found match :
ck = Y
tgtKey and tgtVal == Y, 1
val pruneWithKeyValue : string * int -> json:NestedMap -> NestedMap
val pruned : NestedMap =
Object
(map
[("A", Object (map [("C", Value 10); ("D", Value 30); ("S", Value 20)]));
("B",
Object
(map
[("G", Value 30);
("H",
Object
(map [("E", Value 100); ("F", Value 300); ("S", Value 200)]));
("I", Value 40); ("S", Value 50)])); ("Y", Value 1)])
val remainsTheSame : bool = true
The code says that the output data structure remains unchanged (val remainsTheSame : bool = true). Even more interestingly, somehow the keyvalue tuple that contains the key-value pair the function is searching got modified:
>>> Found match :
ck = Y
tgtKey and tgtVal == Y, 1
This is the problem. In fact, if I hardcode the keyvalue tuple:
let rec pruneWithKeyValue (keyvalue: string * int) (json: NestedMap) =
let condition ck cv =
let tgtKey = (fst keyvalue)
let tgtVal = (snd keyvalue)
match (ck, cv) with
| ("S", NestedMap.Value(20)) ->
printfn ">>> Found match : "
printfn " ck = %s " ck
printfn " tgtKey and tgtVal == %s, %i" tgtKey tgtVal
true
| _ -> false
match json with
| NestedMap.Object nmap ->
if (nmap |> Map.exists (fun k v -> condition k v)) then
json
else
printfn "Expanding w keyvalue: (%s,%i): " (fst keyvalue) (snd keyvalue)
let expanded = nmap |> Map.map (fun k v -> pruneWithKeyValue keyvalue v)
NestedMap.Object(expanded |> Map.filter (fun k v -> v <> NestedMap.Object (Map.empty)))
| _ -> NestedMap.Object (Map.empty)
let pruned = pruneWithKeyValue ("S",20) l1
let remainsTheSame = (pruned = l1)
results in (yeah) the desired result:
Expanding w keyvalue: (S,20):
>>> Found match :
ck = S
tgtKey and tgtVal == S, 20
Expanding w keyvalue: (S,20):
Expanding w keyvalue: (S,20):
val pruneWithKeyValue : string * int -> json:NestedMap -> NestedMap
val pruned : NestedMap =
Object
(map
[("A", Object (map [("C", Value 10); ("D", Value 30); ("S", Value 20)]))])
val remainsTheSame : bool = false
It may be trivial but I don't understand where and how keyvalue ends up being modified, preventing me from getting the right output with parametric key-value tuple.
You can't pattern match against existing variables, in your original code tgtKey and tgtVal will be new bindings, not related to the existing ones which will be shadowed.
So change your match:
match (ck, cv) with
| (tgtKey, NestedMap.Value(tgtVal)) ->
to:
match (ck, cv) with
| (k, NestedMap.Value v) when (k, v) = (tgtKey, tgtVal) ->
or just:
match (ck, cv) with
| x when x = (tgtKey, NestedMap.Value(tgtVal)) ->

Find unique array of tuples

I have 4 arrays of different data. For the first array of string, I want to delete the duplicate element and get the results of array of unique tuples with 4 elements.
For example, let's say the arrays are:
let dupA1 = [| "A"; "B"; "C"; "D"; "A" |]
let dupA2 = [| 1; 2; 3; 4; 1 |]
let dupA3 = [| 1.0M; 2.0M; 3.0M; 4.0M; 1.0M |]
let dupA4 = [| 1L; 2L; 3L; 4L; 1L |]
I want the result to be:
let uniqueArray = [| ("A", 1, 1.0M, 1L); ("B", 2, 2.0M, 2L); ("C", 3, 3.0M, 3L); ("D",4, 4.0M, 4L) |]
You will first need to write a zip4 function which will zip the arrays:
// the function assumes the 4 arrays are of the same length
let zip4 a (b : _ []) (c : _ []) (d : _ []) =
Array.init (Array.length a) (fun i -> a.[i], b.[i], c.[i], d.[i])
Then a distinct function for arrays, using Seq.distinct:
let distinct s = Seq.distinct s |> Array.ofSeq
And the result would be:
> zip4 dupA1 dupA2 dupA3 dupA4 |> distinct;;
val it : (string * int * decimal * int64) [] =
[|("A", 1, 1.0M, 1L); ("B", 2, 2.0M, 2L); ("C", 3, 3.0M, 3L);
("D", 4, 4.0M, 4L)|]
let zip4 s1 s2 s3 s4 =
Seq.map2 (fun (a,b)(c,d) ->a,b,c,d) (Seq.zip s1 s2)(Seq.zip s3 s4)
let uniqueArray = zip4 dupA1 dupA2 dupA3 dupA4 |> Seq.distinct |> Seq.toArray

Resources