I am looking at the following C# code:
static readonly byte[] OnFrame = { 0x01 };
static readonly byte[] OffFrame = { 0x02 };
Can someone tell me how that would be written in FSharp?
In F# you (almost) don't need to specify types (unless you want to), and values are by default immutable (i.e. you don't need to specify readonly either). Array declaration is denoted using the pipe-bracket syntax [| |].
Whether or not you need explicit static depends on where you're declaring this: if you need this as part of a class, you'll have to do static member, otherwise you can just do let. And I would strongly urge you to ask yourself: do you really need it as part of a class?
All above said, this would be the code:
let OnFrame = [| 0x01uy |]
let OffFrame = [| 0x02uy |]
(the uy part means "unsigned byte"; without it the values will be int)
I would also strongly urge you to consider if you really need an array or a list would suffice, but I can't tell definitively without knowing broader context.
The same way you'd specify any other array in F#: using [| |] syntax.
byte literals use uy postfix, and hexadecimal literals use 0x prefix:
let onFrame = [| 0x01uy |]
let offFrame = [| 0x02uy |]
You can see more on MSDN: Literals (F#).
Related
I've done most of my development in C# and am just learning F#. Here's what I want to do in C#:
string AddChars(char char1, char char2) => char1.ToString() + char2.ToString();
EDIT: added ToString() method to the C# example.
I want to write the same method in F# and I don't know how to do it other than this:
let addChars char1 char2 = Char.ToString(char1) + Char.ToString(char2)
Is there a way to add concatenate these chars into a string without converting both into strings first?
Sidenote:
I also have considered making a char array and converting that into a string, but that seems similarly wasteful.
let addChars (char1:char) (char2: char) = string([|char1; char2|])
As I said in my comment, your C# code is not going to do what you want ( i.e. concatenate the characters into a string). In C#, adding a char and a char will result in an int. The reason for this is because the char type doesn't define a + operator, so C# reverts to the nearest compatable type that does, which just happens to be int. (Source)
So to accomplish this behavior, you will need to do something similar to what you are already trying to do in F#:
char a = 'a';
char b = 'b';
// This is the wrong way to concatenate chars, because the
// chars will be treated as ints and the result will be 195.
Console.WriteLine(a + b);
// These are the correct ways to concatenate characters into
// a single string. The result of all of these will be "ab".
// The third way is the recommended way as it is concise and
// involves creating the fewest temporary objects.
Console.WriteLine(a.ToString() + b.ToString());
Console.WriteLine(Char.ToString(a) + Char.ToString(b));
Console.WriteLine(new String(new[] { a, b }));
(See https://dotnetfiddle.net/aEh1FI)
F# is the same way in that concatenating two or more chars doesn't result in a String. Unlike C#, it results instead in another char, but the process is the same - the char values are treated like int and added together, and the result is the char representation of the sum.
So really, the way to concatenate chars into a String in F# is what you already have, and is the direct translation of the C# equivalent:
let a = 'a'
let b = 'b'
// This is still the wrong way (prints 'Ã')
printfn "%O" (a + b)
// These are still the right ways (prints "ab")
printfn "%O" (a.ToString() + b.ToString())
printfn "%O" (Char.ToString(a) + Char.ToString(b))
printfn "%O" (String [| a;b |]) // This is still the best way
(See https://dotnetfiddle.net/ALwI3V)
The reason the "String from char array" approach is the best way is two-fold. First, it is the most concise, since you can see that that approach offers the shortest line of code in both languages (and the difference only increases as you add more and more chars together). And second, only one temporary object is created (the array) before the final String, whereas the other two methods involve making two separate temporary String objects to feed into the final result.
(Also, I'm not sure if it works this way as the String constructors are hidden in external sources, but I imagine that the array passed into the constructor would be used as the String's backing data, so it wouldn't end up getting wasted at all.) Strings are immutable, but using the passed array directly as the created String's backing data could result in a situation where a reference to the array could be held elsewhere in the program and jeopardize the String's immutability, so this speculation wouldn't fly in practice. (Credit: #CaringDev)
Another option you could do in F# that could be more idiomatic is to use the sprintf function to combine the two characters (Credit: #rmunn):
let a = 'a'
let b = 'b'
let s = sprintf "%c%c" a b
printfn "%O" s
// Prints "ab"
(See https://dotnetfiddle.net/Pp9Tee)
A note of warning about this method, however, is that it is almost certainly going to be much slower than any of the other three methods listed above. That's because instead of processing array or String data directly, sprintf is going to be performing more advanced formatting logic on the output. (I'm not in a position where I could benchmark this myself at the moment, but plugged into #TomasPetricek's benckmarking code below, I wouldn't be surprised if you got performance hits of 10x or more.)
This might not be a big deal as for a single conversion it will still be far faster than any end-user could possibly notice, but be careful if this is going to be used in any performance-critical code.
The answer by #Abion47 already lists all the possible sensible methods I can think of. If you are interested in performance, then you can run a quick experiment using the F# Interactive #time feature:
#time
open System
open System.Text
let a = 'a'
let b = 'b'
Comparing the three methods, the one with String [| a; b |] turns out to be about twice as fast as the methods involving ToString. In practice, that's probably not a big deal unless you are doing millions of such operations (as my experiment does), but it's an interesting fact to know:
// 432ms, 468ms, 472ms
for i in 0 .. 10000000 do
let s = a.ToString() + b.ToString()
ignore s
// 396ms 440ms, 458ms
for i in 0 .. 10000000 do
let s = Char.ToString(a) + Char.ToString(b)
ignore s
// 201ms, 171ms, 170ms
for i in 0 .. 10000000 do
let s = String [| a;b |]
ignore s
I think that's a well-known limitation of F# but I couldn't find any good workarounds…
So, here is the code (I tried to make it as simple as possible, so probably it looks like it doesn't make any sense):
[<ReflectedDefinition>]
type Human (makeAName: unit -> string) as self =
let mutable cats : Cat array = [| |]
do
// get a cat
cats <- Array.append cats [| new Cat (self, makeAName ()) |]
member this.Cats = cats
and
[<ReflectedDefinition>]
Cat (owner : Human, name : string) = class end
The compiler says:
error FS0452: Quotations cannot contain inline assembly code or pattern matching on arrays
Actually it is the combination of as self and array property getter that breaks everything.
The points here are:
I really want to use arrays, because I want WebSharper to translate my collections to JavaSript arrays.
I really need a self-identifier in constructors.
I really need classes (i.e. functional style won't work).
Per-method self-identifiers (member this.Foo) work fine.
One workaround I can think of is making constructors private and using static methods to construct objects. This way I don't need as self. But it is just silly.
Are there any better options?
Update:
Here is an even simpler example:
[<ReflectedDefinition>]
type User (uid: int) as self =
let ROOT_UID = 0
member this.isRoot = (uid = ROOT_UID)
With as self I can't even define a class constant. Well, it's actually a separate question, but I'll ask it here: how do I define a class constant in this particular case?
I do not think it is silly at all. We actually prefer static constructor methods for clarity, even in code that does not use WebSharper. In the whole IntelliFactory codebase we rarely, if ever use self.
You are hitting two annoying limitations of F# compiler and quotations. As you point out, static methods can solve the self problem:
[<ReflectedDefinition>]
type Human private (cats: ref<Cat []>) =
member this.Cats = !cats
static member Create(makeAName: unit -> string) =
let cats = ref [| |]
let h = Human(cats)
let cat = Cat(h, makeAName())
cats := [| cat |]
h
and [<ReflectedDefinition>] Cat (owner: Human, name: string) =
class
end
There are many other ways to accomplish this, for example you can get rid of ref indirection.
Second, you often get FS0452 in ReflectedDefinition code with array operations, even in plain static methods. This usually can be resolved by using library functions instead of direct array access (Array.iter, Array.map).
For the second example, you really want this:
[<ReflectedDefinition>]
module Users =
[<Literal>]
let ROOT_UID = 0
type User(uid: int) =
member this.isRoot = (uid = ROOT_UID)
The [<Literal>] annotation will let you pattern-match on your constants, which can be handy if there is more than one.
For your points:
I really want to use arrays - that should be OK
I really need a self-identifier - it is never necessary, just as constructors are not
I really need classes (i.e. functional style won't work) - definitely not true
Per-method self-identifiers (member this.Foo) work fine - yes, and are useful
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.
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
I am just a beginner in programing i wish covert some code from C# to F#,
I have encotered this code:
float[] v1=new float[10]
I need to use this pointer to pass to the function:
ComputeBuffer<float> bufV1 =
new ComputeBuffer<float>(Context, ComputeMemoryFlags.ReadWrite |
ComputeMemoryFlags.UseHostPointer, v1);
If i creat an array in F# like this:
let v1 = [| 1.0..10.0 |]
and call now the funaction like this:
let bufV1 = new ComputeBuffer<float>(Context,
ComputeMemoryFlags.ReadWrite |||
ComputeMemoryFlags.UseHostPointer, v1)
Is it an error?? How do i pass a pointer??
(In .NET, we call these things references to objects; v1 is a reference to an array object. Pointers are something different.)
Note that what F# refers to as float is what C# calls a double. You might need
let v1 = [| 1.0f .. 10.0f |]
where the f suffix makes the values be F# float32s (e.g. C# floats).
not an error.
Need to point out that v1 is not a pointer, it is an object in .Net.