Can I extend built-in array's indexer? - f#

I want to add my own indexer to generic array type:
type 'T``[]`` with
member this.Item(x: string) = 1 // test
However, this gives a compile error "expression was expected to have type int but here has type string (FS0001)."
let a = [|1|]
let b = a.["aa"] // error: FS0001
let c = a.Item("aa") // this works.
I found this question which was asked 3 years ago and the answer suggested it's an FSharp bug. Want to confirm if it is still the case, or whether the specification has been updated since then?

I got this question answered by Don Syme here:
The specification needs to be clarified that indexers for arrays may not be extended.
I'd say the suggestion to allow them is best tracked via http://fslang.uservoice.com. That said, it is not simple to do this, because array indexers are "built in" to the compiler and have no F# or IL metadata representation.
So it's not supported in Fsharp.

Related

How to use Akka.Streams.*.ConcatMany in F#?

I want to create a flow that creates a new source (it will be a persistence query) out of incoming elements, and then flattens the results. Something like this simplified example:
var z = Source.Single(1).ConcatMany(i => Source.Single(i));
this code compiles and works as expected. My problem is that when I translate it to F#:
let z = Source.Single(1).ConcatMany(fun i -> Source.Single(i))
I get an error saying
This expression was expected to have type
'IGraph<SourceShape<'a>,Akka.NotUsed>'
but here has type
'Source<int,Akka.NotUsed>'
I think that the cause of that is that F# handles co/contravariance differently than C# and cannot simply convert these generic specializations (https://github.com/fsharp/fslang-suggestions/issues/162), but I cannot figure out a way to make a convertion between an int and a SourceShape<int>. Is it possible to convert this example to F#?
Looking at the code on GitHub, it appears that Source<TOut, TMat> is a direct implementation of IGraph, so you should just be able to cast it:
public sealed class Source<TOut, TMat> : IFlow<TOut, TMat>, IGraph<SourceShape<TOut>, TMat>
let z = Source.Single(1).ConcatMany(fun i -> Source.Single(i) :> IGraph<SourceShape<int>,Akka.NotUsed>)
I think the biggest difference between the C# and F# usage is that C# will automatically do the upcast for you.
One workaround that I found is to use Akkling.Streams wrapper library:
open Akkling.Streams
let x =
Source.singleton 1
|> Source.collectMap(fun x -> Source.singleton x)
the question how to do this without Akkling remains open.

FSharp.Data.JsonProvider - Getting json from types

The FSharp.Data.JsonProvider provides a means to go from json to an F# type. Is it possible to go in the reverse direction i.e. declare an instance of one of the types created by FSharp.Data.JsonProvider, set the field values to be what I need, and then get the equivalent json?
I've tried things like this,
type Simple = JsonProvider<""" { "name":"John", "age":94 } """>
let fred = Simple(
Age = 5, // no argument or settable property 'Age'
Name = "Fred")
The latest version of F# Data now supports this. See the last example in http://fsharp.github.io/FSharp.Data/library/JsonProvider.html.
Your example would be:
type Simple = JsonProvider<""" { "name":"John", "age":94 } """>
let fred = Simple.Root(age = 5, name = "Fred")
This is one area where C# has an edge over F#, at least in Visual Studio. You can copy your JSON example code into the clipboard and in Visual Studio use the Edit -> Paste Special -> Paste JSON As Classes and it will create a class to match the JSON example. From there you can easily use the class in F#.
More details on paste special here
Hopefully a matching feature will come for F# soon too.

Couchbase queries using composite keys in F#

How would one translate the following composite key query:
?stale=false&connection_timeout=60000&limit=10&skip=0&startkey=["Default",{}]&endkey=["Default"]&descending=true
to couchbase .net api when using F#. I found a similar using C# LINQ here
Couchbase .Net Library complex startKey/endKey types, but how can I accomplish the same using F#?
The missing parts are the ???
let result = myView.Descending(true).Stale(StaleMode.False).Limit(limit).StartKey( ??? ).EndKey( ??? )
Any help would be appreciated.
It appears that you're asking how to create an array in F#. To declare an object array in F# do this:
let (startKey: Object array) = [|35; 23; new Object()|]
let (endKey: Object array) = [|35; 23|]
Note that normally the type specification isn't needed, but since you're mixing types in the array, the compiler will assume the type of the first object in the array (int) and so the new Object() would cause a compile error. Adding the type specification fixes that issue.
let result = myView.Descending(true).Stale(StaleMode.False).Limit(limit).StartKey( startKey ).EndKey( endKey )

Why is F# inferring my function implements IComparable?

I'm a hobbyist programmer (cook by trade) that's currently trying to teach myself F# and functional programming in general.
Anyway, I was fooling around with DeflateStream and wrote the following two functions:
let Compress compressMe =
let ds = new DeflateStream(File.Create("compressed.txt"), CompressionMode.Compress)
File.OpenRead(compressMe).CopyTo(ds)
ds.Close()
let Decompress =
let ds = new DeflateStream(File.OpenRead("compressed.txt"), CompressionMode.Decompress)
ds.CopyTo(File.Create("decompressed.txt"))
ds.Close()
In the body of the main function they are called one right after the other like this:
Compress args.[0]
Decompress
However, if compressed.txt doesn't exist when the program is run Decompress throws a FileNotFoundException which is surprising because the only thing that could throw this is the call to File.OpenRead("compress.txt"). After about an hour I figured out that Decompress was implementing IComparable and was being executed before the call to it in the main function. I found that by changing its definition to let Decompress () = [...] it no longer implemented IComparable and my code executed as it was intended to. Can anyone tell me why F# was infering IComparable and why such and inference would cause the function to execute before the main function marked with [<EntryPoint>]? Also, please forgive the imperitive style of my code, I'm incredibly new at this.
Thanks in adavance.
I'm not entirely sure about the IComparable bit, but the issue you have is that without the parentheses, the compiler is treating Decompress as a value not a function. This would be similar to if you had written.
let compressedName = "compressed.txt"
in that case, compressedName is now a value. Adding the parentheses tells the compiler that this is a function whose code must be called each time the function is rather than a value initialized once (before the entry point) by the code you wrote.
When you write something like
let value =
//some long calculation
[<Entrypoint>]
let main args = ...
The compiler executes the long calculation before main. This is because you probably use the value later in your code. To suppress this, as you found, you need to use let value() = ....
I am not sure where Icomparable is coming from, but this is the key to what is happening.
Note, if you write
let a = ...
let b = ...
The compiler will gurantee a is calculated before b executes.
As others have pointed out, the absence of parentheses in the declaration is significant.
let Decompres = ...
declares a variable of type unit. This type is used to represent "data" (even if this data doesn't encode much information), and it implements IComparable like any other data-oriented type.
let Decompress() = ...
declares a function, and functions in F# are not comparable, probably because there is no universally accepted notion of equality on functions.
I can't see that the "IComparable-ness" of Decompress had anything to do with the exception you got.

Visual studio - f# - Error FS0588 : Block following this 'let' is unfinished. Expect expression

i have got several times , trying to implement different functions, the message you see as title. I would like to know if anyone can tell me the general meaning (and reason) of this error message. As i mentioned before, i have got the problem several times and manage to fix it, but still didnt get the exact reason, so i will not post any specific code.
Thank you in advance
The most common case when you may get this error is when you write let binding that is not followed by an expression that calculates the result. In F#, everything is an expression that returns some result, so if you write let a = 10 it is generally not a valid expression. To make it valid, you need to return something:
let foo () =
let a = 10
() // return unit value (which doesn't represent any information)
The only exception where you can write just let a = 10 is a global scope of an F# source file - for example, inside a module declaration or in an F# script file. (This is why the declaration of foo above is valid).
It is difficult to give any advice without seeing your code, but you probably have a let declaration that is not followed by an F# expression.
Out of curiosity, the following example shows that let can really be used inside an expression (where it must return some meaningful result):
let a = 40 + (let a = 1
a + a)

Resources