I'm guessing you want something like this?
let toB = function A x -> B (float x) | x -> x let toA = function B x -> A (int x) | x -> x let allA = Aonly |> List.map toA let allB = Aonly |> List.map toB
Let me explain the problem in an other way.
I will not use it on such a "ABC" type and convert numeric types.
// If we extend the DU, there are more possibilities/directions to transform: AtoB, CtoA, ..
type ABC =
| A of int
| B of float
| C of decimal
// So the transformations should be parametrized, like this
let XtoY X Y f = function X n -> Y (f n) | n -> n // not working
// I can't get the X and Y functions as parameters.
Note: This example is choosen to have an unwrapper X and a wrapper Y that will be needed as parameter.I will not use it on such a "ABC" type and convert numeric types.
It is actually possible to use reflection to implement this. However, this is very hacky and probably very inefficient too. I write it here because it's fun to see in action, but you should not use it in anything remotely serious.
EDIT: For the sake of playing with reflection, here is a version that works with a multiple-valued constructor:
open Microsoft.FSharp.Reflection
let XtoY (X: 'a -> 't) (Y: 'b -> 't) (f: 'a -> 'b) =
let xInfo, _ = FSharpValue.GetUnionFields(X Unchecked.defaultof<'a>, typeof<'t>)
function n ->
let nInfo, nValues = FSharpValue.GetUnionFields(n, typeof<'t>)
if xInfo.Tag = nInfo.Tag then
Y (f (nValues.[0] :?> 'a))
else
n
// example use.
type ABC =
| A of int
| B of float
| C of decimal
let AtoB = XtoY A B float
AtoB (A 12) // = B 12.
Also, it doesn't work if A takes multiple values (ex. A of int * int), because in this case Unchecked.defaultof returns null, and multiple-value constructors throw an exception when passed null.EDIT: For the sake of playing with reflection, here is a version that works with a multiple-valued constructor:
open Microsoft.FSharp.Reflection
let XtoY (X: 'a -> 't) (Y: 'b -> 't) (f: 'a -> 'b) =
let dummy =
if FSharpType.IsTuple typeof<'a> then
let tupleTypes = FSharpType.GetTupleElements typeof<'a>
let tupleValues = Array.zeroCreate<obj> tupleTypes.Length
FSharpValue.MakeTuple(tupleValues, typeof<'a>) :?> 'a
else Unchecked.defaultof<'a>
|> X
let xInfo, _ = FSharpValue.GetUnionFields(dummy, typeof<'t>)
fun n ->
let nInfo, nValues = FSharpValue.GetUnionFields(n, typeof<'t>)
if xInfo.Tag = nInfo.Tag then
let a =
if nValues.Length = 1 then
nValues.[0] :?> 'a
else
FSharpValue.MakeTuple(nValues, typeof<'a>) :?> 'a
Y (f a)
else
n
type AB =
| A of int * float
| B of int * int
let AtoB = XtoY A B (fun (x, y) -> x, x)
AtoB (A (32, 2.)) // = B (32, 32)
It seems to be not possible without Reflection.
I marked it as answer.
I marked it as answer.
Ah, I think I understand better now. The problem is that A, B, C are constructors, i.e. functions int -> ABC, float -> ABC, etc.; but what you need here are functions that tell you if some instance of ABC is an A or not, etc. So:
let isA = function A x -> Some x | _ -> None let isB = function B x -> Some x | _ -> None let isC = function C x -> Some x | _ -> None let XtoY X Y f a = match X a with Some n -> Y (f n) | _ -> a let AtoB = XtoY isA B // (int -> float) -> ABC -> ABC let BtoC = XtoY isB C // (float -> decimal) -> ABC -> ABC
Yeah, that, but I don't want to write 3 functions like isA, isB and isC (DRY!),
I want also to parametrize this isX function, to be fully parametric.
And that's the hard part. Because in isX, the constructor is used as a pattern matcher, and I didn't found a way to parametrize that.
I want also to parametrize this isX function, to be fully parametric.
And that's the hard part. Because in isX, the constructor is used as a pattern matcher, and I didn't found a way to parametrize that.
Unfortunately, the F# compiler does not generate these "extractor" functions automatically. This is similar to a getter in a partial lens, and in Scala they're using macros to generate this boilerplate; in Haskell they're using Template Haskell AFAIK.
Not sure what you mean by "fully parametric". As I defined it, XtoY is parametric, for example the parameter X used to extract a value is of type 'a -> 'b option
Not sure what you mean by "fully parametric". As I defined it, XtoY is parametric, for example the parameter X used to extract a value is of type 'a -> 'b option
Thank you for your fast responses!!
Ahh that's a shame : "Unfortunately, the F# compiler does not generate these "extractor" functions automatically."
This one is some kind related: [link:stackoverflow.com]
Where to find more information about that?
Have you found a workaround for the "partial lenses"?
Ahh that's a shame : "Unfortunately, the F# compiler does not generate these "extractor" functions automatically."
This one is some kind related: [link:stackoverflow.com]
Where to find more information about that?
Have you found a workaround for the "partial lenses"?
If the only thing you need now is a parameterized function to tell you if an object is of some union case X in ABC, all you need to do is type test. Internally, union cases are implemented as distinct classes (per specification). Identical union cases will always be of the same type, and differing union case will be of differing types. I think there are some exceptions to this, but they are, well, exceptional.
You cannot access the types directly (at least, not normally -- you could acquire them using reflection). However, you only need to get an instance for this to work.
BTW, the tester properties IsA, IsB, IsC actually exist. Per specification, the compiler generates static factory methods, testers, and some other things for interop with CLI.
They are invisible to F#, however. Member constraints will also fail to recognize them. However, you can see them if you enable 'Show raw object properties' in the Debug options or if you use reflection. I think it will also work if you use late binding but I'm not sure.
You cannot access the types directly (at least, not normally -- you could acquire them using reflection). However, you only need to get an instance for this to work.
type ABC = | A of int | B of int let isX (abc1 : ABC) (abc2 : ABC) = abc1.GetType() = abc2.GetType() let t1,t2,t3 = isX (A 1) (A 5), isX (A 1) (B 5), isX (B 5) (A 5) //This will give true,false,false
BTW, the tester properties IsA, IsB, IsC actually exist. Per specification, the compiler generates static factory methods, testers, and some other things for interop with CLI.
They are invisible to F#, however. Member constraints will also fail to recognize them. However, you can see them if you enable 'Show raw object properties' in the Debug options or if you use reflection. I think it will also work if you use late binding but I'm not sure.
Topic tags
- f# × 3660
- compiler × 263
- functional × 199
- c# × 119
- websharper × 114
- classes × 96
- web × 94
- book × 84
- .net × 82
- async × 72
- parallel × 43
- server × 43
- parsing × 41
- testing × 41
- asynchronous × 30
- monad × 28
- ocaml × 26
- tutorial × 26
- haskell × 25
- workflows × 22
- html × 21
- linq × 21
- introduction × 19
- silverlight × 19
- wpf × 19
- fpish × 18
- collections × 14
- pipeline × 14
- templates × 12
- monads × 11
- opinion × 10
- reactive × 10
- plugin × 9
- scheme × 9
- sitelets × 9
- solid × 9
- basics × 8
- concurrent × 8
- deployment × 8
- how-to × 8
- python × 8
- complexity × 7
- javascript × 6
- jquery × 6
- lisp × 6
- real-world × 6
- workshop × 6
- xaml × 6
- conference × 5
- dsl × 5
- java × 5
- metaprogramming × 5
- ml × 5
- scala × 5
- visual studio × 5
- formlets × 4
- fsi × 4
- lift × 4
- sql × 4
- teaching × 4
- alt.net × 3
- aml × 3
- enhancement × 3
- list × 3
- reflection × 3
- blog × 2
- compilation × 2
- computation expressions × 2
- corporate × 2
- courses × 2
- cufp × 2
- enterprise × 2
- entity framework × 2
- erlang × 2
- events × 2
- f# interactive × 2
- fsc × 2
- google maps × 2
- html5 × 2
- http × 2
- interactive × 2
- interface × 2
- iphone × 2
- iteratee × 2
- jobs × 2
- keynote × 2
- mvc × 2
- numeric × 2
- obfuscation × 2
- oop × 2
- packaging × 2
- pattern matching × 2
- pipelines × 2
- rx × 2
- script × 2
- seq × 2
- sockets × 2
- stm × 2
- tcp × 2
- trie × 2
- type × 2
- type provider × 2
- xna × 2
- zh × 2
- .net interop × 1
- 2012 × 1
- abstract class × 1
- accumulator × 1
- active pattern × 1
- addin × 1
- agents × 1
- agile × 1
- android × 1
- anonymous object × 1
- appcelerator × 1
- architecture × 1
- array × 1
- arrays × 1
- asp.net 4.5 × 1
- asp.net mvc × 1
- asp.net mvc 4 × 1
- asp.net web api × 1
- aspnet × 1
- ast × 1
- b-tree × 1
- bistro × 1
- bug × 1
- camtasia studio × 1
- canvas × 1
- class × 1
- client × 1
- clojure × 1
- closures × 1
- cloud × 1
- cms × 1
- coding diacritics × 1
- color highlighting × 1
- combinator × 1
- confirm × 1
- constructor × 1
- continuation-passing style × 1
- coords × 1
- coursera × 1
- csla × 1
- css × 1
- data × 1
- database × 1
- declarative × 1
- delete × 1
- dhtmlx × 1
- discriminated union × 1
- distance × 1
- docs × 1
- documentation × 1
- dol × 1
- domain × 1
- du × 1
- duf-101 × 1
- eclipse × 1
- edsl × 1
- em algorithm × 1
- emacs × 1
- emotion × 1
- error × 1
- etw × 1
- euclidean × 1
- event × 1
- example × 1
- ext js × 1
- extension methods × 1
- extra × 1
- facet pattern × 1
- fantomas × 1
- fear × 1
- float × 1
- fp × 1
- frank × 1
- fsdoc × 1
- fsharp.core × 1
- fsharp.powerpack × 1
- fsharpx × 1
- function × 1
- functional style × 1
- gc × 1
- generic × 1
- geometry × 1
- getlastwin32error × 1
- google × 1
- group × 1
- hash × 1
- history × 1
- hosting × 1
- httpcontext × 1
- https × 1
- hubfs × 1
- ie 8 × 1
- if-doc × 1
- inheritance × 1
- installer × 1
- interpreter × 1
- io × 1
- ios × 1
- ipad × 1
- kendo × 1
- learning × 1
- licensing × 1
- macro × 1
- macros × 1
- maps × 1
- markup × 1
- marshal × 1
- math × 1
- metro style × 1
- micro orm × 1
- minimum-requirements × 1
- multidimensional × 1
- multithreading × 1
- mysql × 1
- mysqlclient × 1
- nancy × 1
- nested × 1
- nested loops × 1
- node × 1
- object relation mapper × 1
- object-oriented × 1
- offline × 1
- option × 1
- orm × 1
- osx × 1
- owin × 1
- paper × 1
- parameter × 1
- performance × 1
- persistent data structure × 1
- phonegap × 1
- pola × 1
- powerpack × 1
- prefix tree × 1
- principle of least authority × 1
- programming × 1
- projekt_feladat × 1
- protected × 1
- provider × 1
- ptvs × 1
- quant × 1
- quotations × 1
- range × 1
- raphael × 1
- razor × 1
- rc × 1
- real-time × 1
- reference × 1
- restful × 1
- round table × 1
- runtime × 1
- scriptcs × 1
- scripting × 1
- service × 1
- session-state × 1
- sitelet × 1
- stickynotes × 1
- stress × 1
- strong name × 1
- structures × 1
- tdd × 1
- template × 1
- tracing × 1
- tsunamiide × 1
- type inference × 1
- type providers × 1
- upload × 1
- vb × 1
- vb.net × 1
- vector × 1
- visual f# × 1
- visual studio 11 × 1
- visual studio shell × 1
- visualstudio × 1
- web api × 1
- webapi × 1
- windows 8 × 1
- windows-phone × 1
- winrt × 1
- xml × 1
|
Copyright (c) 2011-2012 IntelliFactory. All rights reserved. Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us |
Built with WebSharper |
or in other words
How to parametrize the unwrap and wrap type of Discriminated Union types?
type AB = | A of int | B of float let Aonly = [A 3; A 5] // there are no B // unwrap A and wrap it into B Aonly |> List.map (function A i -> B (float i)) = [B 3.0; B 5.0] // true // how to parametrize A and B? let f (source:AB) (target:AB) = function (source:AB) i -> (target:AB) (float i) // how to parametrize A and B? Aonly |> List.map (f A B)