The short answer is yes: you have to write a separate function for each primitive numeric data type you want to support.
You can use the name of a numeric type as a function to convert to this numeric type. E.g., if you wanted to pass an int to the int64 version of factorial.
1 2 3
val factoriali64 : int64 -> int64 factoriali64 (int64 5)
F# supports some overloading in certain contexts. As zakaluka points out it supports OO-style overloading with the OverloadID attribute, but this only works on methods of classes not functions (afaik). Another form of overloading is with inline functions -- this is how operator overloading (e.g. +) is implemented in F#.
To write a truly generic factorial function, you could write something like this
1 2 3 4 5 6 7 8 9 10 11 12
open Math open GlobalAssociations let rec factorial (n : INumeric<_>) a = if a = n.Zero || a = n.One then n.One else n.Multiply(a, factorial n (n.Subtract(a, n.One))) let i32 = factorial (GetNumericAssociation ()) 5 let i64 = factorial (GetNumericAssociation ()) 5L let f = factorial (GetNumericAssociation ()) 5.0 let b = factorial (GetNumericAssociation ()) 5I
To this factorial function you need to pass an INumeric<'a> object which contains methods for addition, multiplication, etc. on the type 'a. To get a default implemenation for this interface for primitive numeric types you call the GetNumericAssociation function. However you can write your own implemenations of this interface for your own custom types and use it with this factorial function too.
Actually you're real close to a fully generic solution here:
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
#light open Math open GlobalAssociations let inline factorial (n : 'a) = let a : INumeric<'a> = GetNumericAssociation() let rec factorial n = if n = a.Zero || n = a.One then a.One else n * factorial (n - a.One) factorial n factorial 10 |> printf "%A\n" factorial 10L |> printf "%A\n" factorial 10.0 |> printf "%A\n" factorial 10.0f |> printf "%A\n" val inline factorial : ^a -> ^a when ^a : (static member ( * ) : ^a * ^a -> ^a) and ^a : (static member ( - ) : ^a * ^a -> ^a) 3628800 3628800L 3628800.0 3628800.0f
Cheers,
Andy
Welcome to the forums. You are correct, in that F# has great similarities to OCaml (and can still cross-compile F# code into OCaml bytecode).
Unlike OCaml, F# does support overloading in certain situations. For example, the same operator is used for addition for all the different types (+), as opposed to OCaml where you have (+) for integers and (+.) for floating point numbers.
The question you asked here is quite tricky. For one thing, F# does not perform automatic casting from int to int64 and vice versa (or between any two types of numbers, for that matter). Also, numbers are written differently for different types (1, 1., 1L, 1I, 1N, 1y, 1uy, ...). These different representations of the same constant cannot be compared directly, but must be explicitly type-cast first.
So, for your problem, you would have to do some extra work. Here is one way you could do it:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
#light type Factorial = | Vali of int | Valf of float static member ( * ) (x: Factorial, y: Factorial) = match x, y with | Vali(a), Vali(b) -> Vali(a * b) | Valf(a), Valf(b) -> Valf(a * b) | _ -> failwith "shouldn't happen" let helper a = match box a with | :? int as x -> Vali(x) | :? float as x -> Valf (x) | _ -> failwith "type not supported" let fact a = let rec f' b = match b with | Vali(x) -> if x = 0 then Vali(1) else b * (f' (helper (x - 1))) | Valf(x) -> if x = 0. then Valf(1.) else b * (x - 1. |> helper |> f') f' <| helper a
As you can see, I basically created a new Factorial type that supports the multiplication operator (*). If you wanted to add another type, say, bigint, you would have to add it to the type definition, the (*) operator, the helper function and the internal f' function. However, if you look at the signature of fact, you see that it is val fact : 'a -> Factorial. This means that it will take a value of any type (since fact sends the argument to helper, which immediately boxes it). Here are some sample outputs:
1 2 3 4 5 6 7 8 9
> fact 5;; val it : Factorial = Vali 120 > fact 5.;; val it : Factorial = Valf 120.0 > fact 5L;; Microsoft.FSharp.Core.FailureException: type not supported at FSI_0006.helper[T](T a) at <StartupCode$FSI_0012>.FSI_0012._main() stopped due to error
A more reasonable solution may be to use the BigInt type.
1 2 3 4 5 6 7 8 9 10 11 12 13
open Microsoft.FSharp.Math let fact2 a = let helper x = match box x with | :? int as y -> BigInt.of_int y | :? int64 as y -> BigInt.of_int64 y | :? string as y -> BigInt.of_string y | _ -> failwith "unsupported type" let rec f' b = if b = 0I then 1I else b * (f' (b - 1I)) helper a |> f'
The code is much shorter. Here is some sample output:
1 2 3 4 5 6 7 8 9 10
> fact2 5;; val it : bigint = 120I > fact2 5L;; val it : bigint = 120I > fact2 5.;; Microsoft.FSharp.Core.FailureException: unsupported type at <A href="mailto:FSI_0014.helper@1114@1114[U](U">FSI_0014.helper@1114@1114[U](U</A> x) at FSI_0014.fact2[T](T a) at <StartupCode$FSI_0017>.FSI_0017._main() stopped due to error
Hope this helps,
z.
helper a |> f'
That line is the only part I don't understand. Does it call helper and force it to act as the argument to the f' function? That is, the |> says to input the result of helper a into f', or am I just confusing myself? I can't find anything on this |> combination, so I'm wondering what its purpose is. Is it a separate operator from | and > or does it combine them? <:^)>
Edit: I found my answer in a PDF document that the Wikipedia entry on F# linked to.
I figured things out a bit - like the fact that it is nearly impossible to do anything without the experimental lightweight feature...
Here is my final code:
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
#light open Microsoft.FSharp.Math (* the actual factorial function *) let fac n = (* 'x' is just a variable that holds the BigInt value of 'n' *) let x = match box n with | :? int as y -> BigInt.of_int y | :? int64 as y -> BigInt.of_int64 y | :? string as y -> BigInt.of_string y | _ -> failwith "Unsupported" (* the recursive function that does the work *) let rec f a = if (a = 0I or a = 1I) then 1I else a * (f (a - 1I)) (* calling the recursive function *) f x (* the main program (I can't stand the I at the end so I convert the BigInt to a string) *) printf "%s" (BigInt.to_string (fac 20))
This was really mind-boggling when I tried to figure it out without using #light. I had no clue how to use the 'in' statements to make it happy, though I figured out the semicolon parts at least. :P
Like someone said in another post I read earlier, the lightweight dialect will probably become the default. Without it, it is just too difficult in my opinion.
That looks about right. However, note that the solution I showed above is quite verbose and only really useful when dealing with numbers of different types.
For a more generic solution, see the use of the OverloadID attribute. You can see some more information about it at:
[link:cs.hubfs.net]
[link:cs.hubfs.net]
There's also a little bit about it on Page 136 of Expert F# (Don Syme's book).
Regards,
z.
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 |
From what I can tell, this is a relatively new language with some roots in Caml. Caml requires different functions for different types (e.g. factoriali for int, factorialf for float, factoriali64 for int64 -> int64 or whatever...)
Is F# the same way? Do I have to create separate functions for
int -> int64
int -> int
int64 -> int
int64 -> int64
or is there a way I can use some form of type recognition? The reason I ask is because I was just getting into the language when I found that I can't do something like:
and make it return int64 when I pass it an int64. Actually, it won't even accept int64 as an argument! I realize there is the (n:int64) explicitly-specified form, but that means it will refuse to accept int arguments then!
Is there any way around this issue where I can call the function using factorial(4) or factorial(400L) ?