I know this is not very F# like, but I would like to do the following
[a; b; c; d]
|> Async.Parallel
|> Async.RunSynchronously
|> ignore
where a, b, c and d are generated by a function like this
let myasync (stringparameter: string) = [async{some_code}]
where some_code is for getting information from Internet and saving to database. The function itself should return nothing (returns unit).
I want to create [a,b,c,d] by using
let mutable mylist = []
for i in [1..n] do
myfunction
mylist <- List.append mylist myfunction
I got the error: The expression was expected to have type 'a list' but here has type 'string -> Async list'
Any help would be greatly appreciated thanks!
The immediate error you are seeing is because List.append wants 2 list parameters, it's not like Array.Add(), you can fix it by doing the following:
let mutable mylist = []
for i in [1..n] do
myfunction
mylist <- List.append mylist [myfunction]
However, there are more succinct ways to do this without using mutability. Example:
let mylist =
[ for i in [1..n] do
let myfunction() =
async {
// your code
return () }
yield myfunction ]
Related
I have the following code:
let exchangeInfo, marginBrackets, accountInfo =
async {
let failOrExtract = function
| Ok d -> d
| Error (e: ExchangeError) -> e.Describe |> tee logger.Fatal |> failwith
let pf = processResult >> failOrExtract
let! e = rest.FuturesUsdt.System.GetExchangeInfoAsync() |> Async.AwaitTask
let! b = rest.FuturesUsdt.GetBracketsAsync() |> Async.AwaitTask
let! i = rest.FuturesUsdt.Account.GetAccountInfoAsync() |> Async.AwaitTask
return pf e, pf b, pf i
} |> Async.RunSynchronously
In short, it calls 3 async rest functions, then sends them through failOrExtract which is made of 2 parts: the processResult part that returns a Result<'a, ExchangeError> type, with 'a different for each of these calls, and then failOrExtract that either fails or returns the data field.
this will not compile, the compiler says:
[FS0001] The type 'BinanceFuturesUsdtExchangeInfo' does not match the type 'System.Collections.Generic.IEnumerable<BinanceFuturesSymbolBracket>'```
It looks like the failOrExtract function was generic on the first use, but not afterwards since pf e compiles, but pf b and pf i have the same error.
why am I getting this error?
I think you're running into the F# "value restriction", although the compiler isn't being clear about it. The problem here is that pf is defined as a value, not a function, so the compiler is inferring that it has a concrete, non-generic type. In order to give pf a generic signature, try changing it to this instead:
let pf x = x |> processResult |> failOrExtract
I'm using quite a lot this piece of code:
let inline (||>) (a: 'a option) (b: 'a -> unit) = if a.IsSome then b a.Value
so I can do things like
myData ||> DoSomethingWithIt
without having to test if myData is Some or None since there are many functions that don't generally need to test for an option. This avoid to put the test in the function itself.
I would like to extend this to methods of a type where I could do like C#'s:
myData?.DoSomethingWithIt
essentially replacing:
if myData.IsSome then myData.Value.DoSomethingWithIt
with some syntactic sugar.
but I have no idea how I could do the operator so that it allows to get access to the type's method in the expression. Is that possible in F#?
I'm also open to learn about why it could be a bad idea if it is :)
Depending on your return type of DoSomethingWithIt the F# library offers a few standard functions for working with Options that can be turned into operators.
let x = Some 1
let aPrinter a = printfn "%i" a
let add1 a = a + 1
let (|?>) opt f = Option.iter f opt
let (|??>) opt f = Option.map f opt
x |?> aPrinter
let y = x |??> add1
You can also consider redefining your DoSomethingWithIt to work with an option by partial application.
let DoSomethingWithIt' = Option.iter DoSomethingWithIt
let something' = Option.iter (fun (b:B) -> b.DoSomethingWithIt()) //For instance methods
That may end up being a lot of work depending how many functions you are dealing with.
Ultimately you shouldn't try to hide the fact you are working with Options. By making something an Option you are telling the compiler that you aren't sure whether it exists or not. It is trying to help you by forcing you to deal with the None case. If there are lots of cases in your code where you know your Option is Some then there's probably a larger architectural issue in your code and you should try to lift all your Option<'T> to just T prior to doing work with them. e.g.:
let lift xs =
[
for x in xs do
match x with
| Some x -> yield x
| None -> ()
]
Have a look at Option.iter. It has the same signature as your operator.
There is no analogical syntax for such constructions but F# have alternatives.
The easiest way is to use FSharpx.Extras library and FSharpx.Option.maybe computation expression which will allow you to use Option related operations.
open FSharpx.Option
let a = Some 1
let b = maybe {
let! v = a
return v + 3
} // b is (Some 4)
let c : int option = None
let d = maybe {
let! v = c
return v + 3 // this line won't be reached
} // d is None
I believe that the ?. operator in c# is a syntactic sugar that hides the if statement checking for null before invoking a member of the type. Even if you could make it work the way you plan, I feel that it would go against the FP principles and could cause more problems down the line.
The Option module contains probably most of what you need already. The iter function allows to call a function on the value of the Option if that value is present (Some).
If you have situation that your input parametes can be nulls, but not options, you can use the Option.ofObj function that will convert the parameter to an Option with Some if the parameter is not null, else None.
So assuming that your function DoSomethingWithit accepts a string and returns unit:
let DoSomethingWithIt = //(string -> unit)
printf "%s; "
You can use this more verbose syntax to (for example) iterate over nullable values in your list:
let lst = [ "data"; "data 2"; null; "data3" ]
lst
|> List.iter (fun v -> v |> Option.ofObj |> Option.iter DoSomethingWithIt)
Alternatively you can compose the Optioni.ofObj and Option.iter DoSomethingWithIt functions and do something like
let SafeDoSomethingWithIt = //(string -> unit)
Option.ofObj >> Option.iter DoSomethingWithIt
This gives you safe invocation:
let lst2 = [ "data"; "data 2"; null; "data3" ]
lst2
|> List.iter SafeDoSomethingWithIt
You can generalize the combination of the functions returning unit (but not only)
let makeSafe fn =
Option.ofObj >> Option.iter fn
Then you can create a series of safe functions:
let SafeDoSomethingWithIt = makeSafe DoSomethingWithIt
let safePrint = makeSafe (printf "%s; ")
//...etc
Then this still works:
lst2
|> List.iter SafeDoSomethingWithIt
lst2
|> List.iter safePrint
You can also write a wrapper for functions returning values using Option.bind function.
let makeSafeReturn fn = //(string -> string option)
Option.ofObj >> Option.bind fn
I'm trying to do the following in F#, from pseudo C# code:
Data? MyFunc(a, b, c) { ... }
var result = new List<Data>();
foreach (var i in MyData)
{
var r = MyFunc(something, somethingelse, i);
if (r != null) result.add((Data)r);
}
I have 2 questions:
Is there an equivalent of List.filter that will allow to check if the result of my function call is None or not?
How can I invoke a function through a list if some of the parameters do not come from the list iterator? like something and somethingelse in my example?
(beginning in F#, the answer may be trivial)
You can use List.choose:
let myData a b c = ...
let collect somthing somethingElse myData =
myData |> List.choose (myFunc something somethingElse)
If the list element is not the last element to myFunc you can't use partial application but can use a function e.g.
myData |> List.choose (fun e -> myFunc something e somethingElse)
I am completely at loss why this code doesn't mutate a member variable in a sequence of types:
for p in prescrs do
p.ATC <- "A"
for c in p.Drug.Components do
for s in c.Substances do
s.DoseTotal.Adjust <- adjustKg
s.DoseTotal.Time <- "DAY"
s.DoseTotal.Unit <- s.DrugConcentration.Unit
s.DoseRate.Adjust <- adjustKg
s.DoseRate.Time <- "DAY"
s.DoseRate.Unit <- s.DrugConcentration.Unit
prescrs is a sequence of Prescriptions which is a very simple 'POCO' defined as a type with member values. I don't have clue why this doesn't work.
I tried a simple test case like:
type IterTest () =
member val Name = "" with get, set
member val IterTests = [] |> List.toSeq : IterTest seq with get, set
let iterseq =
[
new IterTest(Name = "Test1")
new IterTest(Name = "Test2")
]
|> List.toSeq
iterseq |> Seq.iter(fun x -> x.IterTests <- iterseq)
iterseq |> Seq.iter(fun x ->
x.IterTests
|> Seq.iter(fun x' -> x'.Name <- "itered"))
But here the result is as expected. So, can't even quite reproduce my problem???
Found a solution (without really understanding the problem above). When I first convert the prescrs sequence to a list like:
let prescrs = prescrs |> Seq.toList
and then do the imperative looping, properties do get mutated.
Try this sample:
type Mutable() =
member val Iterated = false with get, set
let muts = Seq.init 5 (fun _ -> printfn "init"; Mutable())
let muts2 = muts // try again with let muts2 = muts |> List.ofSeq
printfn "Before iter"
for a in muts2 do
printfn "iter"
a.Iterated <- true
printfn "After iter"
muts2 |> List.ofSeq
and check how iter and init are interleaved.
Seqs are lazy, but are not cached once computed. So even if you imperatively try to mutate some of the elements in your prescrs sequence, it all goes away once you pull prescrs again. If you change prescrs into a concrete collection type like list before doing the mutation, you no longer hit the same problem. Note that things might get even trickier if what you have is a seq inside a seq inside a seq.
The best idea would be to avoid mutation in the first place though.
This is a follow-up question to this question.
I'm trying to create a computation expression builder that accumulates a value through custom operations, and also supports standard F# language constructs at the same time. For the purposes of having a simple example to talk about, I'm using a computation expression that builds F# lists. Thanks to suggestions from kvb and Daniel I'm further along, but still having trouble with for loops.
The builder:
type Items<'a> = Items of 'a list
type ListBuilder() =
member x.Yield(vars) = Items [], vars
member x.Run(l,_) = l
member x.Zero() = Items [], ()
member x.Delay f = f()
member x.ReturnFrom f = f
member x.Combine((Items curLeft, _), (Items curRight, vars)) =
(Items (curLeft # curRight), vars)
member x.Bind(m: Items<'a> * 'v, f: 'v -> Items<'a> * 'o) : Items<'a> * 'o =
let (Items current, vals) = m
x.Combine(m, f vals)
member x.While(guard, body) =
if not (guard()) then
x.Zero()
else
x.Bind(body, fun () -> x.While(guard, body))
member x.TryWith(body, handler) =
try
x.ReturnFrom(body())
with e ->
handler e
member x.TryFinally(body, compensation) =
try
x.ReturnFrom(body())
finally
compensation()
member x.Using(disposable:#System.IDisposable, body) =
let body' = fun() -> body disposable
x.TryFinally(body', fun () ->
match disposable with
| null -> ()
| disp -> disp.Dispose())
member x.For(xs:seq<'a>, body) =
x.Using(xs.GetEnumerator(), fun enum ->
x.While(enum.MoveNext, x.Delay(fun () -> body enum.Current)))
[<CustomOperation("add", MaintainsVariableSpace=true)>]
member x.Add((Items current, vars), [<ProjectionParameter>] f) =
Items (current # [f vars]), vars
[<CustomOperation("addMany", MaintainsVariableSpace=true)>]
member x.AddMany((Items current, vars), [<ProjectionParameter>] f) =
Items (current # f vars), vars
let listBuilder = ListBuilder()
let build (Items items) = items
This version allows for things I could not do before, such as:
let stuff =
listBuilder {
let x = 5 * 47
printfn "hey"
add x
addMany [x .. x + 10]
} |> build
However, I'm still getting a compiler error on this one:
let stuff2 =
listBuilder {
for x in 1 .. 50 do
add x
} |> build
In this case, the IDE is underlining the x in for x in and telling me, "This expression was expected to have type unit, but here has type int."
It's not really clear to me why it's expecting the loop variable to be of type unit. Clearly I've got the wrong method signature somewhere, and I suspect I'm not passing through my accumulated state in every place I should be, but the compiler error is really not helping me narrow down where I went wrong. Any suggestions would be appreciated.
The immediate cause is that your While function constrains the type of body. However, in general you can't use both custom operations and also control flow operators in the same computation expression, so I don't think you'll ever be able to do exactly what you want even if you fix the signature.