Let's say I have a value defined as a sort of commission formula
let address_commission = 1.0 // minimal simplified example
and I want to apply the above said commission to an amount I'm reading from the DB (the code is from a window WCF service I have in production)
let address_commission = 1.0 // minimal simplified example
new Model.ClaimModel(
//RequestRow = i, recounting
Code = (row.["claim_code"] :?> string),
EvtDate = (row.["event_date"] :?> DateTime),
// skipping lines...
Amount = (row.["amount"] :?> double) * address_commission,
now I see that the amount line compiles fine, but I also need to include the same commission in the following
PrevAmount = (if row.IsNull("prev_amount") then Nullable() else (row.["prev_amount"] :?> Nullable<double>)),
which is wrong since The type 'float' does not match the type 'obj'
Therefore I've tried also
PrevAmount = (if row.IsNull("prev_amount") then Nullable() else (((row.["prev_amount"] :?> double) * address_commission) :?> Nullable<double>)),
but it also fails with The type 'double' does not have any proper subtypes and cannot be used as the source of a type test or runtime coercion.
What is the correct way to handle this?
:?> is a dynamic cast and it's only checked at run-time so better try to avoid it. If you are accessing databases it helps to open the open FSharp.Linq.NullableOperators namespace. (The link is gone for me but it's somewhere on docs or msdn). Then you can use ?*? and similar operators. For example:
let x = System.Nullable<float> 4.
let y = x ?* 3.0
//val y : System.Nullable<float> = 12.0
You can have ? on either or both sides.
You will get back a Nullable float which you can coerce to an option with
Option.ofNullable(y) or to a double float y.
I'm going to use only one type coercion and wrap it within a Nullable(...)
PrevAmount = (if row.IsNull("prev_amount") then Nullable() else Nullable((row.["prev_amount"] :?> double) * address_commission)),
It compiles and looks ok to me, but I'm still open to different answers if they are more correct than mine
Related
Let's say I wanted to have an alias of sprintf, I would simply do this:
namespace FSharp
module Core =
let specialsprintf x y =
sprintf x y
This would bring me the same compilation-time advantages (compared to its C# cousin API System.String.Format) of sprintf such as type-checking, checking number of parameters passed is correct, etc.
However, let's say I wanted to disable this compilation-time niceties and write a simple version of sprintf by calling String.Format underneath. Could this be possible? I know the goal sounds stupid but I want to do this mental exercise to make sure I understand how F# typing works here. If I do this (supposing we only can pass one parameter):
namespace FSharp
module Core =
let specialsprintf x y =
#if NORMAL_FSHARP
sprintf x y
#else
let x = x.Replace("%s", "{0}")
System.String.Format(x,y)
#endif
It doesn't even compile, the error is:
~/FSharpPlayground.fs(17,17): Error FS0072: Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. (FS0072) (FSharpPlayground)
Mmmm why?
Ok, if I specify the type like this:
namespace FSharp
module Core =
let specialsprintf
#if NORMAL_FSHARP
x
#else
(x: string)
#endif
y =
#if NORMAL_FSHARP
sprintf x y
#else
let x = x.Replace("%s", "{0}")
System.String.Format(x,y)
#endif
Then I end up with a compilation error in the caller:
~/FSharpPlaygroundUse.fs(48,48): Error FS0001: This expression was expected to have type 'obj []' but here has type 'string' (FS0001)
I guess I need now to qualify the type of y now, but not sure how to do it in case I wanted to extend it to be able to use 2 arguments instead of just 1 (I don't manage to make it work with the ParamArray attribute). Something tells me that I probably also need an uncurry function but I'm a bit lost :-/
I'm assuming that what you want is something like sprintf but variadic, and without type checking the format.
There's no 'uncurrying' or variable argument functions for F#, unfortunately.
That being said, there's the option of using a parameter array. ParamArray is only valid on class members not bindings, so we can settle for a static member which is similar in scope to a let fn () =.
type SpecialPrint =
static member sprintf (format, [<ParamArray>] args) =
let index = ref -1
let stringFormat = Regex.Replace(format, "%[a-z]", (fun _ -> sprintf "{%d}" (Interlocked.Increment index)))
String.Format(stringFormat, args)
With;
let result = SpecialPrint.sprintf ("Hello %s%s", "World", "!") //Hello World!
let a = ref 0
let f (x: byref<int>) = x
f a // type error
System.Int32.TryParse("123",a) // works
f a being a type error is puzzling to me since a can be passed into .NET library methods with a byref<int> type. Why?
Edit: I think I really explained the question poorly. The type of System.Int32.TryParse is string * byref<int> -> bool and yet it works. So why can't I pass a into a function of type x:byref<int> -> int? That is all I am asking.
This feature is described in section 8.13.7 of the F# spec. The ability to use a ref when a byref is expected is enabled by a "type-directed conversion", but these are applied only on member invocations, not on regular function applications.
The only thing I am seeing wrong with that code is the Type Annotation is incorrect, try :int ref instead of byref<int>
Full code:
let a = ref 0
let f (x: int ref) = x
f a // type error
System.Int32.TryParse("123",a) // works
Edit:
Sorry, I misunderstood your question. So this one is a bit vague on F#'s part, I do think F# needs to improve it's error messages a bit. What is happening is since C# did not originally have tuples, they needed out parameters in order to return multiple values. So when you see a signature like byref<int>, that is .NET's way of telling you that is the signature of an out parameter, out parameters are for C# only. More reading here.
Is it possible to "extend" the F# compiler to do custom compile-time string checks? I'm thinking of something similar to the checks on StringFormat strings when using sprintf etc. When I say "extend", I don't mean build a custom version of the compiler, I mean use existing supported techniques.
Off the top of my head, you might have a RegexFormat type. You provide the regex and the compiler would do the static analysis using the regex. E.g.
//Setup RegexFormat with IP address regex and type abbreviation IpRegexFormat?
//Compile error. ipAddress expects IpRegexFormat!
let ip = ipAddress "192.168.banana.1"
If not, maybe this is a type provider for me :) - If the whole thing is a terrible idea, let me know!
We have a Regex type provider in Fsharpx.
Here are some samples:
type PhoneRegex = Regex< #"(?<AreaCode>^\d{3})-(?<PhoneNumber>\d{3}-\d{4}$)">
[<Test>]
let ``Can call typed IsMatch function``() =
PhoneRegex.IsMatch "425-123-2345"
|> should equal true
[<Test>]
let ``Can call typed CompleteMatch function``() =
PhoneRegex().Match("425-123-2345").CompleteMatch.Value
|> should equal "425-123-2345"
[<Test>]
let ``Can return AreaCode in simple phone number``() =
PhoneRegex().Match("425-123-2345").AreaCode.Value
|> should equal "425"
[<Test>]
let ``Can return PhoneNumber property in simple phone number``() =
PhoneRegex().Match("425-123-2345").PhoneNumber.Value
|> should equal "123-2345"
It's not exactly what you are looking for, but I guess you could easily take this type provider and customize it with your static literal rules.
I think here the real answer is to use a DU -
type ip =
|IP of byte * byte * byte * byte
member x.ToString() =
match x with
|IP(a,b,c,d) -> sprintf "%i.%i.%i.%i"
Then the compile time check is just
let actualip = IP(1uy,1uy,1uy,1uy).ToString()
The easiest solution is to do what the BCL have done with Uri, Guid, etc and create a type that parses a string input.
I think modifying the compiler, while interesting, is overkill (a "terrible idea," as you say).
A similar question has been asked before.
Probably a silly question, but I just got started with F# and I've got a little problem.
Say I have a function like this:
let multiplyByTwo x = x * 2
When I call this like this:
let result = multiplyByTwo 5
Everything is alright, the result is 10.
When I call it like this:
let result = multiplyByTwo 2.5
I expect to get 5 or 5.0 as a result. The actual result however is this:
let result = multiplyByTwo 2.5;;
---------------------------------^^^
stdin(4,28): error FS0001: This expression was expected to have type
int
but here has type
float
Because I want this function to be somewhat generic (i.e. accept both floating point numbers and integers), I don't like this. My question of course: how does one solve this?
When you write a numeric literal in F# (such as 2 or 3.14), the compiler treats that as a value of a specific type and so code that uses numeric literals will not be polymorphic. You can either convert input to a single type and work with that type (like float in desco's answer) or use more advanced features of F#...
Certain numeric operations can be written in a polymorphic way, if you mark the code as inline (this way, the compiler can represent additional constraints and statically resolve them) and if you only use polymorphic primitives (with additional static constraints).
Standard operators are polymorpic in inline functions and the F# library provides a way to get polymorphic value representing 1 and 0 (though not 2), but that's enough to write the function you wanted:
let inline twoTimes n =
let one = LanguagePrimitives.GenericOne
n * (one + one)
twoTimes 2
twoTimes 2.0
If you want to make this nicer, you can define a numeric literal (see Daniel's answer to earlier StackOverflow question) and then you can actually write just:
let inline twoTimes n = n * 2G
The special numeric literal 2G is translated to a call to a function of NumericLiteralG which sums specified number of generic 1 values using the technique I used above (so it won't be efficient for large numbers!) For more information, you see also my recent article on writing generic numeric code in F#.
let inline mulBy2 x = (float x) * 2.0
let a = mulBy2 3 // 6.0 : float
let b = mulBy2 2.5 // 5.0 : float
let c = mulBy2 "4" // 8.0 : float
If you aren't afraid using "little hacks", this might be useful:
// Copied from Core.LanguagePrimitives.IntrinsicFunctions.retype
[<NoDynamicInvocation>]
let inline retype (x:'a) : 'b = (# "" x : 'b #)
let inline multiplyByTwo (x:'a) = x * (retype 2:'a)
// use
let result1 = multiplyByTwo 5 // 10
let result2 = multiplyByTwo 2.5 // 5.0
This construct is not type safe since type checking is done in runtime. Also, quotations are relatively slow.
I'm just wondering if somebody can explain to me how to pass reference cells to functions that are not class members. I've been following the msdn page msdn reference cells
I have the following code:
let myint = ref 32
let mutable myint2 = 23
type addone() =
member t.myadd1func (x:int byref) =
x <- x + 1
let myadd1func (x:int byref) =
x <- x + 1
let adder = new addone()
adder.myadd1func myint
// myadd1func myint <---- this line does not compile
myadd1func &myint2 // <----- this line does though
printfn "%d" !myint
printfn "%d" myint2
My question is... what is the fundamental difference between the call I am making to the "Myadd1func" method on the class and the "myadd1func" function defined after it?
As I write this, I'm guessing that the function doesn't like having .net object references being passed to it as this might break compatibility with other IL components?? I don't mind using a mutable value, I just like to understand these things.
Thanks
I think the byref type in F# should be used only for interoperability purpsoes where the existing features (as explained by kvb) are good enough. If you want to declare a function that modifies some argument passed to it, I would just use ordinary reference cell (e.g. int ref type):
let myadd1func (x:int ref) =
x := !x + 1
let myint = ref 10
myadd1func myint
This may be slightly slower than using byref type (together with local mutable value), but I don't think it is needed very often in functional style, so it should be fine.
This is explained in the Type-directed Conversions at Member Invocations section of the F# specification. For interoperability with other .NET components, ref cells can be passed to members taking byref parameters and the compiler will automatically treat it as the dereferencing of the cell's contents field. However, this isn't done for let-bound functions, and you should directly use the addressof operator (&). You can still use a ref cell, but you have to explicitly dereference the contents field yourself, so this should work in your example: myadd1func &myint.contents