returning variables F#(canopy) easiest way - f#

member x.Logovani(window : string) =
let weburl = ref ""
let actwindow = ref ""
"Login" &&& fun _ ->
browser.SwitchTo().Window(window) |> ignore
weburl := currentUrl()
actwindow := browser.CurrentWindowHandle
return {|weburl,actwindow|}
end
Hello my question is how to pass weburl and actwindoweasiest way, because the way of my return is not working. I want to call function Logovani pass to that function var window and then recieved weburl and actwindow

so finally i fixed it like this
member x.Logovani(window : string) : string ref =
let weburl = ref ""
browser.SwitchTo().Window(window) |> ignore
weburl := currentUrl()
weburl
end

Related

Railway programming F#

I am trying to use the railway programming in F# using result as described in Scott Wlaschin's book 'Domain modeling made functional'. Normally a function has the structure
let functionName parameter : Result<ResultType, ErrorType> =
result {
let! resultValue = someValidationAndTransformation parameter
return resultValue
}
But I want to return also some calculated fields, in both to Ok and the Error case. The best I could come up with was
let functionName parameter : Result<ResultType, ErrorType> * CalculatedFields =
let mutable calculatedFields = {some defaultvalue}
let result =
result {
let! resultValue = someValidationAndTransformation parameter
let calculatedField = someCalculation resultValue
calculatedFields <- {calculatedFields with calculatedField}
return resultValue
}
result, calculatedFields
This mutable field does not look nice. Is there a better way to get the calculated fields in both Ok and Error case?
I would use a match in this situation:
let functionName parameter : Result<ResultType, ErrorType> * CalculatedFields =
let result = someValidationAndTransformation parameter
let calculatedFields =
match result with
| Ok x -> someCalculation x
| Error e -> { some defaultvalue }
result, calculatedFields

The F# equivalent of C#'s 'out'

I am rewriting a C# library to F# and I need to translate the following code
bool success;
instance.GetValue(0x10, out success);
what is the equivalent of the out keyword in F#?
Neither wasatz's answer nor Max Malook's is complete. There are three ways of calling methods with out parameters. The second and third ways also work with ref parameters.
For the examples, assume the following type:
open System.Runtime.InteropServices //for OutAttribute
type SomeType() =
member this.GetValue (key, [<Out>] success : bool byref) =
if key = 10 then
success <- true
"Ten"
else
success <- false
null
Assume also that we have an instance of that type:
let o = SomeType()
Option 1
You can let the F# compiler handle the out parameter by tupling it with the return value:
let result1, success1 = o.GetValue 10
let result2, success2 = o.GetValue 11
Running the above lines in F# interactive yields
val success1 : bool = true
val result1 : string = "Ten"
val success2 : bool = false
val result2 : string = null
Option 2
You can use a mutable value, passing its address with the & operator:
let mutable success3 = false
let result3 = o.GetValue (10, &success3)
let mutable success4 = false
let result4 = o.GetValue (11, &success4)
In F# interactive, the result is
val mutable success3 : bool = true
val result3 : string = "Ten"
val mutable success4 : bool = false
val result4 : string = null
This option is best when you are delegating to another method, since you can pass the calling method's out parameter directly to the called method. For example, if you are implementing a wrapper around IDictionary<_,_>, you can code the TryGetValue method as
//...
interface IDictionary<'TKey, 'TValue> with
member this.TryGetValue (key, value) = inner.TryGetValue (key, &value)
//...
Option 3
You can use a reference cell:
let success5 = ref false
let result5 = o.GetValue (10, success5)
let success6 = ref false
let result6 = o.GetValue (11, success6)
The output:
val success5 : bool ref = {contents = true;}
val result5 : string = "Ten"
val success6 : bool ref = {contents = false;}
val result6 : string = null
Warning!
Be careful not to use the ref keyword as you would in C# for an in/out parameter. For example, the following does not yield the desired result:
let success7 = false
let result7 = o.GetValue (10, ref success7)
The output:
val success7 : bool = false
val result7 : string = "Ten"
Why does success7 hold the value false? Because success7 is an immutable variable.
In C#, ref calls attention to the fact that you are passing a reference to a variable as the argument for a ref parameter. It simply serves as insurance that the programmer of the caller is aware that the variable may be modified by the called method. In F# however, ref creates a new reference cell holding a copy of the value of the following expression.
In this case, we are making a reference cell that holds the value copied from the success7 variable, but not assigning that new reference cell to any variable. We then pass that reference cell to the GetValue method, which modifies the content of the reference cell. Because the calling method has no variable pointing to the modified cell, it has no way of reading the new value of the reference cell.
You should probably return an option or a tuple instead. Because F# has pattern matching you really don't need out parameters since there are better ways to return more than one value from a function.
So, something like this would be more idiomatic
let (value, success) = instance.GetValue(0x10)
where instance.GetValue is a
unit -> ('a, bool)
Or you could return an option and do something like
match instance.GetValue(0x10) with
| Some value -> doStuff value
| None -> failwith "Oops!"
You have to use a reference cell.
let success = ref false
instance.GetValue(0x10, success)
// access the value
!success
I think it's also worth mentioning here that the value of the out parameter doesn't have to be initialized.
It is possible to do the following:
let mutable success3 = Unchecked.defaultof<bool>
let result3 = o.GetValue (10, &success3)
This might be usefull in scenarios where you are calling a .NET library function with arrays as output parameters, i.e:
let mutable currFeatures = Unchecked.defaultof<PointF[]>
let mutable status = Unchecked.defaultof<byte[]>
let mutable trackError = Unchecked.defaultof<float32[]>
CvInvoke.CalcOpticalFlowPyrLK(
previousFrame,
nextFrame,
previousPoints,
Size(15,15),
2,
MCvTermCriteria(10, 0.03),
//Out params
&currFeatures,
&status,
&trackError,
//---------
LKFlowFlag.UserInitialFlow)

Reading and updating OpenXML in F#

I can't get this F# code to read and update Content Control text fields inside Word documents.
The second function does absolutely nothing and the first one produces this error: An unhandled exception of type 'System.InvalidOperationException' occurred in System.Core.dll
Additional information: Sequence contains no elements
namespace OpenXML
open DocumentFormat.OpenXml
open DocumentFormat.OpenXml.Packaging
open DocumentFormat.OpenXml.Wordprocessing
open System.Linq
// Add the DocumentFormat.OpenXml assembly
// Add the WindowsBase assembly
module public Word =
let query_plain_text_content_control document_path_and_file_name content_control_tag =
use theDoc = WordprocessingDocument.Open((document_path_and_file_name :string), true)
let mainPart = theDoc.MainDocumentPart
let block = mainPart.Document.Body.Descendants<SdtElement>().Where(fun r -> r.SdtProperties.GetFirstChild<Tag>().Val = content_control_tag).Single()
let t = block.Descendants<Text>().FirstOrDefault()
t.Text
let update_plain_text_content_control document_path_and_file_name content_control_tag new_text = async {
use theDoc = WordprocessingDocument.Open((document_path_and_file_name :string), true)
let mainPart = theDoc.MainDocumentPart
let block = mainPart.Document.Body.Descendants<SdtElement>().Where(fun r -> r.SdtProperties.GetFirstChild<Tag>().Val = content_control_tag).Single()
let t = block.Descendants<Text>().FirstOrDefault()
t.Text <- new_text
mainPart.Document.Save() |> ignore
}
Seems to work fine, with a couple of tweaks:
#r#"DocumentFormat.OpenXml.dll"
#r"WindowsBase.dll"
open DocumentFormat.OpenXml
open DocumentFormat.OpenXml.Packaging
open DocumentFormat.OpenXml.Wordprocessing
open System.Linq
// Add the DocumentFormat.OpenXml assembly
// Add the WindowsBase assembly
module public Word =
let query_plain_text_content_control document_path_and_file_name content_control_tag =
use theDoc = WordprocessingDocument.Open((document_path_and_file_name :string), true)
let mainPart = theDoc.MainDocumentPart
let block = mainPart.Document.Body.Descendants<SdtElement>().Where(fun r -> r.SdtProperties.GetFirstChild<Tag>().Val.ToString() = content_control_tag).Single()
let t = block.Descendants<Text>().FirstOrDefault()
t.Text
let update_plain_text_content_control document_path_and_file_name content_control_tag new_text = async {
use theDoc = WordprocessingDocument.Open((document_path_and_file_name :string), true)
let mainPart = theDoc.MainDocumentPart
let block = mainPart.Document.Body.Descendants<SdtElement>().Where(fun r -> r.SdtProperties.GetFirstChild<Tag>().Val.ToString() = content_control_tag).Single()
let t = block.Descendants<Text>().FirstOrDefault()
t.Text <- new_text
mainPart.Document.Save() |> ignore
}
let oldtext = query_plain_text_content_control #".\text.docx" "ctrltag"
let update = update_plain_text_content_control #".\text.docx" "ctrltag" "new text"
Async.RunSynchronously(update)
let newtext = query_plain_text_content_control #".\text.docx" "ctrltag"
.. on a document containing a single plaintext content control, with tag of 'ctrltag', with content 'old text', I get:
val oldtext : string = "Old text"
val update : Async<unit>
val newtext : string = "new text"
Without calling .ToString() on 'r.SdtProperties.GetFirstChild().Val', I got this error:
The type 'string' is not compatible with the type 'StringValue'.
Perhaps there is a problem with your document? The error you are getting would seem to suggest that there are no content controls with the specified Tag.

Why is the member dictionary in this f# code always empty?

I want to scrape a page for all the urls and put them in the dictionary. I created an class with an dictionary. But I can't seem to add elements into it.
type crawler =
new()= {}
member this.urls = new Dictionary<string,string>()
member this.start (url : string)=
let hw = new HtmlWeb()
let doc = hw.Load(url)
let docNode = doc.DocumentNode
let links = docNode.SelectNodes(".//a")
for aLink in links do
let href = aLink.GetAttributeValue("href"," ")
if href.StartsWith("http://") && href.EndsWith(".html") then
this.urls.Add(href, href)
Why is the dictionary urls empty?
because urls here is property that returns new dictionary on every call.
type Crawler() =
let urls = new Dictionary<string,string>()
member this.Urls = urls
member this.Start (url : string)=
let hw = new HtmlWeb()
let doc = hw.Load(url)
let docNode = doc.DocumentNode
let links = docNode.SelectNodes(".//a")
for aLink in links do
let href = aLink.GetAttributeValue("href"," ")
if href.StartsWith("http://") && href.EndsWith(".html") then
urls.Add(href, href)
This wasn't your question, but if you're interested in taking a more functional approach, here's one way to do it:
type Crawler =
{ Urls : Set<string> }
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module Crawler =
[<CompiledName("Start")>]
let start crawler (url:string) =
let { Urls = oldUrls } = crawler
let newUrls =
HtmlWeb().Load(url).DocumentNode.SelectNodes(".//a")
|> Seq.cast<HtmlNode>
|> Seq.choose (fun link ->
match link.GetAttributeValue("href"," ") with
| href when href.StartsWith("http://") && href.EndsWith(".html") -> Some href
| _ -> None)
|> Set.ofSeq
|> Set.union oldUrls
{ crawler with Urls = newUrls }
Your data and behaviors are now separate. Crawler is an immutable record type. start accepts a Crawler and returns a new one with the updated list of urls. I replaced Dictionary with Set, since the keys and values are the same; eliminated unused let bindings, and snuck in some pattern matching. This should have a relatively friendly interface in C# also.

f# overwrite array access operator .[]

in F#, I want to make a type of indexed array, so I can access the element by either .[i] or .[index_names] and by slice notation with index .. Is it possible to overwrite .[] like this? thanks.
define overloaded indexer in your type:
type MyIndexedArray<'T>() =
member this.Item(i : int) : 'T = Unchecked.defaultof<_>
member this.Item(name : string) : 'T = Unchecked.defaultof<_>
member this.GetSlice(a : int option, b : int option) : 'T = Unchecked.defaultof<_>
let arr = new MyIndexedArray<int>()
let a = arr.[1]
let b = arr.["name"]
let c = arr.[1..2]
let d = arr.[1..]
let e = arr.[..3]
let f = arr.[*]

Resources