The definition and use of an active pattern are completely separate issues.
Defining an active pattern is exactly like defining a function that has a funny name (e.g., (|Foo|Bar|)) so anything goes on the right-hand side. The only thing that is active-patterns-aware here is the mapping of the tags Foo and Bar to the appropriate "anonymous" tags in the Choice type.
When you use an active pattern in a match block, the compiler looks up the function that defines it. E.g., if you use the tag Foo, it will lookup and find the function (|Foo|Bar|). Then it expects this function to conform to a certain type. In this case the result type of the function should be Choice2<_,_>. If its type doesn't unify then you get the compile error here.
Partial multi-case patterns (e.g., (|Foo|Bar|_|)) are not supported by design. You can always define them as function but you'll always get an error when you go to use them.
What I've described is the current implementation. It could change. It is easy to argue that it would be better to check the active pattern at the definition-site not the use-site.
Hello,
your second example is very interesting:
F# specification says: partial active pattern should return choice type, and for case it returns Some a, that result of computation (a) will be used as resolved value, and for case it returns None, original value (applied to active patern function) will be applied to next matching rules.
Can F# team give some explanations?
Your first example is known as a total recognizer or affectionally as a"banana split" (the tags around it look like bananas ;). In the example you give, there's not much point: you should return values (if you have a match) using the tags in the banana split. Say (didn't compile this, experiment a bit):
1
let (|Pos|Neg|) x = if x >= 0 then Pos(x,1) else Neg(x,-1)
Note that both results do not necessarily need to have the same shape. But for any value of the type, you have a match. Hence the total in total recognizer..Your second example is known as a "banana slice", and is useful when the decomposition of your value is not total, i.e. the pattern match does not match all possible values.
1 2
let (|MulThree|_|) inp = if inp % 3 = 0 then Some(inp/3) else None
In that case the compiler should check that you return an option type. Not sure why the compiler does not complain in your first example.Check out this paper for many more examples and the two other kinds of active patterns:[link:research.microsoft.com]
Thanks Kurt - but I think I wasn't explicit enough about my question. I understand the normal uses of these constructions (or, at least I think I do). What puzzled me is what happens when you do something outside the regular use cases.
Your first example is known as a total recognizer
or affectionally as a"banana split" (the tags around it look like
bananas ;). In the example you give, there's not much point: you should
return values (if you have a match) using the tags in the banana split.
Is there any use
for the construction I gave (returning something unrelated to the
tags)? Seems like the answer is no - it compiles, but it's useless. Well, I suppose it's not completely useless, since you can call active patterns as normal functions:
1 2 3 4 5 6 7
let (|Foo|Bar|) x = "BAD DOG!" let t = (|Foo|Bar|) 3;; > t;; val it : string = "BAD DOG!"
But I've never seen call-an-active-pattern-as-a-function talked about anywhere, and it seems unlikely to be useful, even it does work.
Your second example is known as a "banana slice", and is useful when
the decomposition of your value is not total, i.e. the pattern match
does not match all possible values.
1 2let (|MulThree|_|) inp = if inp % 3 = 0 then Some(inp/3) else None
Right, I understand that this is the normal way to use these. There were two weird things in my sample, though. In your example, you have a single tag (Multhree) followed by an underscore. In my code, I had two tags followed by an underscore, and then a return of something other than an option. I can't figure out why those would ever be useful.The answer for both of my original questions may very well be "those are completely useless bits of code - don't do that." I just wanted to make sure.
Thanks Kurt - but I think I wasn't explicit enough about my question. I understand the normal uses of these constructions (or, at least I think I do). What puzzled me is what happens when you do something outside the regular use cases.
I see. Well, what gneverov said. Your examples show nicely that there is little special about active patterns: they are just like first class functions. So you can abstract over them, and even pass them in as parameters to other functions or active patterns (see the link I gave for a cool - and useful - example of that). Other than this educational value I don't see why I would write any active patterns like the one you propose, but of course my imagination may be falling short here ;)Kurt
Thanks -
A combination of kurt and gneverov's comments, plus reading the paper Kurt suggested
([link:research.microsoft.com] - Combining
Total and Ad Hoc Extensible Pattern
Matching in a Lightweight Language Extension, Don Syme, Gregory
Neverov, and James Margetson) helped me understand things quite a bit
better. That paper's well worth reading for the explanations of the various flavors of bananas alone.
The paper did point out one more bit of patterns that I still don't understand. How does the (|Q|_|) match against the (|SomePattern|_|) that's passed in to it?
1 2 3 4 5 6 7 8 9 10 11 12
let Fnord (|Q|_|) inp = match inp with | Q -> true | _ -> false let (|SomePattern|_|) x = printfn "x is %A in the |SomePattern| recognizer" x Some() let y = Fnord (|SomePattern|_|) 10 printfn "y is %A" y
Hi,
I think the way to understand this is to realize that when you declare active pattern, you're just declaring a function with a weird name "|SomePattern|_|" (the parens around the name are used just like when declaring custom operators that also have weird name). This means that you can use active patterns as ordinary functions:
1 2 3 4 5 6 7
> let (|A|_|) a = None;; val ( |A|_| ) : 'a -> 'b option > let f = (|A|_|);; val f : 'a -> 'b option > let (|B|_|) = f;; val ( |B|_| ) : ('a -> 'b option)
So, your "Fnord" function just takes a function as an argument, but since the function has the "right active pattern type" it can reinterpret it as an active pattern, which gives you "pattern names" usable in pattern matching.
Hi,
I think the way to understand this is to realize that when you declare active pattern, you're just declaring a function with a weird name "|SomePattern|_|" (the parens around the name are used just like when declaring custom operators that also have weird name). This means that you can use active patterns as ordinary functions:1 2 3 4 5 6 7> let (|A|_|) a = None;; val ( |A|_| ) : 'a -> 'b option > let f = (|A|_|);; val f : 'a -> 'b option > let (|B|_|) = f;; val ( |B|_| ) : ('a -> 'b option)So, your "Fnord" function just takes a function as an argument, but since the function has the "right active pattern type" it can reinterpret it as an active pattern, which gives you "pattern names" usable in pattern matching.
That makes sense.
And in this case, the "right active pattern type" is just something that has the type ('a -> unit option) - like I was told earlier in this thread, there's nothing special about the results of the active pattern function declaration syntax. This worked just fine:
1 2 3 4 5 6 7
let Fnord (|Q|_|) inp = match inp with | Q -> true | _ -> false let functionReturningSomeUnit = fun x -> Some(x) let fnord2 = Fnord functionReturningSomeUnit ()
So it seems like something that looks like an active pattern (an identifier in banana bars), when it's used as a function argument (the (|Q|_|) in "let Fnord (|Q|_|) inp ="), does two things:
1. It helps set the right arity for the function, and
2. It defines anonymous tags that can be used in the function body.
So it's not quite the same as a regular bound value, since there's no way that I could figure out to get the actual value of the function passed in to that place. (In my code above, I couldn't figure out how I could get at the value of functionReturningSomeUnit, instead of just the tags. Not that I can think of a real use case for doing that, but I was curious.)
Total patterns seem to be the same, where you just pass in something with the right ChoiceX_X signature:
1 2 3 4 5 6 7 8
let Fnord (|Q|Z|) inp = match inp with | Q -> true | _ -> false // >> val Fnord : ('a -> Choice<unit,'b>) -> 'a -> bool let functionReturningChoice (x: unit) = Choice2_1(x) let y = Fnord functionReturningChoice ()
So it seems like something that looks like an active pattern (an identifier in banana bars), when it's used as a function argument (the (|Q|_|) in "let Fnord (|Q|_|) inp ="), does two things:
I'm not sure if I understand correctly, but I think this is possible:
1 2 3 4 5 6 7 8 9
let Foo (|Q|_|) x = // Using pattern names... match x with | Q n -> printfn "%d" n // 'n' is int | _ -> () // Using the bound value as a standard function let res = (|Q|_|) x printfn "%A" res;; // 'res' is option<int>
Now you can call it using function/active pattern as an argument.
For example, you can even do this (id is identity function that just returns the argument):
1 2 3 4 5 6
> Foo id (Some 10);; 10 Some 10 > Foo id None <null>
I can get these expressions to compile. But, I can't seem to make any use of them compile.
In the first case, the compiler seems to not like the fact that a choice is not returned.
In the second case, except for not returning a choice, it seems reasonable. But, I get a compiler error on usage there too: ``partial active patterns may only generate one result.''
Topic tags
- f# × 3705
- websharper × 1897
- compiler × 286
- functional × 201
- ui next × 139
- c# × 121
- classes × 97
- web × 97
- .net × 84
- book × 84
- async × 76
- ui.next × 67
- bug × 54
- core × 49
- website × 49
- server × 45
- parallel × 43
- ui × 43
- enhancement × 41
- parsing × 41
- testing × 41
- trywebsharper × 41
- typescript × 37
- html × 35
- javascript × 35
- owin × 35
- asynchronous × 30
- monad × 28
- ocaml × 28
- tutorial × 27
- warp × 27
- haskell × 26
- sitelet × 25
- linq × 22
- workflows × 22
- wpf × 20
- fpish × 19
- introduction × 19
- silverlight × 19
- sitelets × 19
- monodevelop × 17
- rpc × 17
- suave × 17
- piglets × 16
- collections × 15
- feature request × 15
- jquery × 15
- templates × 15
- getting started × 14
- pipeline × 14
- kendoui × 13
- reactive × 12
- 4.1.0.171 × 11
- monads × 11
- opinion × 10
- 4.0.190.100-rc × 9
- deployment × 9
- fixed × 9
- formlets × 9
- in × 9
- json × 9
- plugin × 9
- proposal × 9
- scheme × 9
- solid × 9
- basics × 8
- concurrent × 8
- highcharts × 8
- how-to × 8
- python × 8
- 4.1.1.175 × 7
- complexity × 7
- documentation × 7
- visual studio × 7
- 4.1.2.178 × 6
- lisp × 6
- real-world × 6
- released in 4.0.192.103-rc × 6
- remoting × 6
- resources × 6
- scala × 6
- websharper ui.next × 6
- workshop × 6
- xaml × 6
- 4.0.193.110 × 5
- 4.2.3.236 × 5
- aspnetmvc × 5
- authentication × 5
- azure × 5
- bootstrap × 5
- conference × 5
- dsl × 5
- formlet × 5
- java × 5
- list × 5
- metaprogramming × 5
- ml × 5
- released in Zafir.4.0.188.91-beta10 × 5
- sql × 5
- visualstudio × 5
- websharper.forms × 5
- zafir × 5
- 4.0.192.106 × 4
- 4.0.195.127 × 4
- 4.1.0.38 × 4
- 4.2.1.86 × 4
- 4.2.6.118 × 4
- css × 4
- example × 4
- extensions × 4
- fsi × 4
- fsx × 4
- html5 × 4
- jqueryui × 4
- lift × 4
- reflection × 4
- remote × 4
- rest × 4
- spa × 4
- teaching × 4
- template × 4
- websocket × 4
- wontfix × 4
- 4.0.196.147 × 3
- 4.1.0.34 × 3
- 4.1.6.207 × 3
- 4.2.1.223-beta × 3
- 4.2.11.258 × 3
- 4.2.4.114 × 3
- 4.2.4.247 × 3
- 4.2.5.115 × 3
- 4.2.6.253 × 3
- 4.2.9.256 × 3
- ajax × 3
- alt.net × 3
- aml × 3
- asp.net mvc × 3
- canvas × 3
- cloudsharper × 3
- compilation × 3
- database × 3
- erlang × 3
- events × 3
- extension × 3
- file upload × 3
- forums × 3
- inline × 3
- issue × 3
- kendo × 3
- macro × 3
- mono × 3
- msbuild × 3
- mvc × 3
- pattern × 3
- piglet × 3
- released in Zafir.4.0.187.90-beta10 × 3
- svg × 3
- type provider × 3
- view × 3
- 4.1.1.64 × 2
- 4.1.5.203 × 2
- 4.1.7.232 × 2
- 4.2.10.257 × 2
- 4.2.3.111 × 2
- 4.2.5.249 × 2
- android × 2
- asp.net × 2
- beginner × 2
- blog × 2
- chart × 2
- client × 2
- client server app × 2
- clojure × 2
- computation expressions × 2
- constructor × 2
- corporate × 2
- courses × 2
- cufp × 2
- d3 × 2
- debugging × 2
- direct × 2
- discriminated union × 2
- docs × 2
- elm × 2
- endpoint × 2
- endpoints × 2
- enterprise × 2
- entity framework × 2
- event × 2
- f# interactive × 2
- fable × 2
- flowlet × 2
- formdata × 2
- forms × 2
- fsc × 2
- google maps × 2
- hosting × 2
- http × 2
- https × 2
- iis 8.0 × 2
- install × 2
- interactive × 2
- interface × 2
- iphone × 2
- iteratee × 2
- jobs × 2
- jquery mobile × 2
- keynote × 2
- lens × 2
- lenses × 2
- linux × 2
- listmodel × 2
- mac × 2
- numeric × 2
- oauth × 2
- obfuscation × 2
- offline × 2
- oop × 2
- osx × 2
- packaging × 2
- pattern matching × 2
- performance × 2
- pipelines × 2
- q&a × 2
- quotation × 2
- reference × 2
- released in Zafir.4.0.185.88-beta10 × 2
- rx × 2
- script × 2
- security × 2
- self host × 2
- seq × 2
- sockets × 2
- stm × 2
- tcp × 2
- trie × 2
- tutorials × 2
- type × 2
- url × 2
- var × 2
- websharper.charting × 2
- websharper4 × 2
- websockets × 2
- wig × 2
- xna × 2
- zh × 2
- .net interop × 1
- 2012 × 1
- 4.0.194.126 × 1
- 4.1.3.184 × 1
- 4.1.4.189 × 1
- 4.2.0.214-beta × 1
- 4.2.12.259 × 1
- 4.2.2.231-beta × 1
- 4.2.8.255 × 1
- Canvas Sample Example × 1
- DynamicStyle Animated Style × 1
- Fixed in 4.0.190.100-rc × 1
- Released in Zafir.UI.Next.4.0.169.79-beta10 × 1
- SvgDynamicAttribute × 1
- WebComponent × 1
- abstract class × 1
- accumulator × 1
- active pattern × 1
- actor × 1
- addin × 1
- agents × 1
- aggregation × 1
- agile × 1
- alter session × 1
- animation × 1
- anonymous object × 1
- apache × 1
- api × 1
- appcelerator × 1
- architecture × 1
- array × 1
- arrays × 1
- asp.net 4.5 × 1
- asp.net core × 1
- asp.net integration × 1
- asp.net mvc 4 × 1
- asp.net web api × 1
- aspnet × 1
- ast × 1
- attributes × 1
- authorization × 1
- b-tree × 1
- back button × 1
- badimageformatexception × 1
- bash script × 1
- batching × 1
- binding-vars × 1
- bistro × 1
- body × 1
- bundle × 1
- camtasia studio × 1
- cas protocol × 1
- charts × 1
- clarity × 1
- class × 1
- cli × 1
- clipboard × 1
- clojurescript × 1
- closures × 1
- cloud × 1
- cms × 1
- coding diacritics × 1
- color highlighting × 1
- color zones × 1
- combinator × 1
- combinators × 1
- compile × 1
- compile code on server × 1
- config × 1
- confirm × 1
- content × 1
- context × 1
- context.usersession × 1
- continuation-passing style × 1
- coords × 1
- cordova × 1
- cors × 1
- coursera × 1
- cross-domain × 1
- csla × 1
- current_schema × 1
- custom content × 1
- data × 1
- data grid × 1
- datetime × 1
- debug × 1
- declarative × 1
- delete × 1
- devexpress × 1
- dhtmlx × 1
- dictionary × 1
- directattribute × 1
- disqus × 1
- distance × 1
- do binding × 1
- doc elt ui.next upgrade × 1
- docker × 1
- dojo × 1
- dol × 1
- dom × 1
- domain × 1
- du × 1
- duf-101 × 1
- dynamic × 1
- eastern language × 1
- eclipse × 1
- edsl × 1
- em algorithm × 1
- emacs × 1
- emotion × 1
- enums × 1
- error × 1
- etw × 1
- euclidean × 1
- eventhandlerlist × 1
- examples × 1
- ext js × 1
- extension methods × 1
- extra × 1
- facet pattern × 1
- failed to translate × 1
- fake × 1
- fantomas × 1
- fear × 1
- float × 1
- form × 1
- form-data × 1
- forum × 1
- fp × 1
- frank × 1
- fsdoc × 1
- fsharp × 1
- fsharp.core × 1
- fsharp.powerpack × 1
- fsharpx × 1
- fsunit × 1
- function × 1
- functional style × 1
- game × 1
- games × 1
- gc × 1
- generic × 1
- geometry × 1
- getlastwin32error × 1
- getting-started × 1
- google × 1
- google.maps × 1
- grid × 1
- group × 1
- guide × 1
- hash × 1
- headers × 1
- hello world example × 1
- heroku × 1
- highchart × 1
- history × 1
- how to × 1
- html-templating × 1
- http405 × 1
- httpcontext × 1
- hubfs × 1
- i18n × 1
- ie 8 × 1
- if-doc × 1
- iis × 1
- image × 1
- images × 1
- inheritance × 1
- initialize × 1
- input × 1
- install "visual studio" × 1
- installer × 1
- int64 × 1
- interfaces × 1
- internet explorer × 1
- interop × 1
- interpreter × 1
- io × 1
- iobservable × 1
- ios × 1
- iot × 1
- ipad × 1
- isomorphic × 1
- javascript optimization × 1
- javascript semanticui resources × 1
- jquery-plugin × 1
- jquery-ui × 1
- jquery-ui-datepicker × 1
- js × 1
- kendo datasource × 1
- kendochart × 1
- kendoui compiler × 1
- knockout × 1
- l10n × 1
- learning × 1
- library × 1
- libs × 1
- license × 1
- licensing × 1
- lineserieszonescfg × 1
- local setting × 1
- localization × 1
- logging × 1
- loop × 1
- macros × 1
- mailboxprocessor × 1
- mapping × 1
- maps × 1
- markerclusterer × 1
- markup × 1
- marshal × 1
- math × 1
- mathjax × 1
- message × 1
- message passing × 1
- message-passing × 1
- meta × 1
- metro style × 1
- micro orm × 1
- minimum-requirements × 1
- mix × 1
- mobile installation × 1
- mod_mono × 1
- modal × 1
- module × 1
- mouseevent × 1
- mouseposition × 1
- multidimensional × 1
- multiline × 1
- multithreading × 1
- mysql × 1
- mysqlclient × 1
- nancy × 1
- native × 1
- nested × 1
- nested loops × 1
- node × 1
- nunit × 1
- object relation mapper × 1
- object-oriented × 1
- om × 1
- onboarding × 1
- onclick × 1
- optimization × 1
- option × 1
- orm × 1
- os x × 1
- output-path × 1
- override × 1
- paper × 1
- parameter × 1
- persistence × 1
- persistent data structure × 1
- phonegap × 1
- pola × 1
- post × 1
- powerpack × 1
- prefix tree × 1
- principle of least authority × 1
- privacy × 1
- private × 1
- profile × 1
- programming × 1
- project × 1
- project euler × 1
- projekt_feladat × 1
- protected × 1
- provider × 1
- proxy × 1
- ptvs × 1
- public × 1
- pure f# × 1
- purescript × 1
- qna × 1
- quant × 1
- query sitelet × 1
- question × 1
- quotations × 1
- range × 1
- raphael × 1
- razor × 1
- rc × 1
- reactjs × 1
- real-time × 1
- ref × 1
- region × 1
- released in 4.0.190.100-rc × 1
- reporting × 1
- responsive design × 1
- rest api × 1
- rest sitelet × 1
- restful × 1
- round table × 1
- router × 1
- routing × 1
- rpc reverseproxy × 1
- runtime × 1
- sales × 1
- sample × 1
- sampleapp × 1
- scriptcs × 1
- scripting × 1
- search × 1
- self hosted × 1
- semanticui × 1
- sequence × 1
- serialisation × 1
- service × 1
- session-state × 1
- sharepoint × 1
- signals × 1
- sitelet website × 1
- sitelet.protect × 1
- sitlets × 1
- slickgrid × 1
- source code × 1
- sqlentityconnection × 1
- ssl × 1
- standards × 1
- static content × 1
- stickynotes × 1
- streamreader × 1
- stress × 1
- strong name × 1
- structures × 1
- submitbutton × 1
- subscribe × 1
- svg example html5 websharper.ui.next × 1
- sweetalert × 1
- system.datetime × 1
- system.reflection.targetinvocationexception × 1
- table storage × 1
- targets × 1
- tdd × 1
- templates ui.next × 1
- templating × 1
- text parsing × 1
- three.js × 1
- time travel × 1
- tls × 1
- tooltip × 1
- tracing × 1
- tsunamiide × 1
- turkish × 1
- twitter-bootstrap × 1
- type erasure × 1
- type inference × 1
- type providers × 1
- type-providers × 1
- typeprovider × 1
- ui next forms × 1
- ui-next × 1
- ui.next jqueryui × 1
- ui.next charting × 1
- ui.next formlets × 1
- ui.next forms × 1
- ui.next suave visualstudio × 1
- ui.next templating × 1
- unicode × 1
- unittest client × 1
- upload × 1
- usersession × 1
- validation × 1
- vb × 1
- vb.net × 1
- vector × 1
- view.map × 1
- visal studio × 1
- visual f# × 1
- visual studio 11 × 1
- visual studio 2012 × 1
- visual studio shell × 1
- vs2017 compiler zafir × 1
- vsix × 1
- web api × 1
- web-scraping × 1
- webapi × 1
- webcomponents × 1
- webforms × 1
- webgl × 1
- webrtc × 1
- webshaper × 1
- websharper async × 1
- websharper codemirror × 1
- websharper f# google × 1
- websharper forms × 1
- websharper reactive × 1
- websharper rpc × 1
- websharper sitelets routing × 1
- websharper warp × 1
- websharper-interface-generator × 1
- websharper.chartsjs × 1
- websharper.com × 1
- websharper.exe × 1
- websharper.owin × 1
- websharper.ui.next × 1
- websharper.ui.next jquery × 1
- websockets iis × 1
- why-websharper × 1
- windows 7 × 1
- windows 8 × 1
- windows-phone × 1
- winrt × 1
- www.grabbitmedia.com × 1
- xamarin × 1
- xml × 1
- yeoman × 1
- yield × 1
- zafir beta × 1
- zafir websharper4 × 1
- zarovizsga × 1
![]() |
Copyright (c) 2011-2012 IntelliFactory. All rights reserved. Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy |
Built with WebSharper |
A couple questions on weird active patterns.
1. Why can active patterns return something other than their choice tags?
let (|Foo|Bar|) x =
(3, 7) // Huh?
(Unsure about terminology here - is "choice tags" the right way to refer to Foo and Bar?)
Seems like this is a useless active pattern - there's no way to use it in a match. Is there a use here that I'm missing?
2. Is there any use for multiple choice tags plus an underscore?
let (|Foo|Bar|_|) x = // Huh? Multiple tags, but ending with underscore?
(3, 7)