Meaning of !! operator in F# (.fsx) [duplicate] - f#

This question already has an answer here:
What does a double exclamation mark (!!) in Fsharp / FAKE?
(1 answer)
Closed 4 years ago.
I'm looking at a FAKE build script that was auto-generated through an FsLab template. In front of one of the strings in a "let" binding, the !! operator is used. What is the meaning of the !! operator?
Looking on the Microsoft Docs F# Symbols and Operator Reference, the !! operator is not listed.
Here is the code in question, the !! operator is in the third-to-last line:
#r "./packages/build/FAKE/tools/FakeLib.dll"
open Fake
open System
let buildDir = "./build/"
let appReferences = !! "/**/*.fsproj"
let dotnetcliVersion = "2.0.2"
let mutable dotnetExePath = "dotnet"
Further down, the appReferences identifier is used as following:
Target "Restore" (fun _ ->
appReferences
|> Seq.iter (fun p ->
let dir = System.IO.Path.GetDirectoryName p
runDotnet dir "restore"
)
)

It takes file pattern and returns a collection of files matching the pattern.

Related

Custom FsCheck Arbitrary type broken in Xunit but working in LINQPad and regular F# program

I'm trying to implement a custom Arbitrary that generates glob syntax patterns like a*c?. I think my implementation is correct, it's just that, when running the test with Xunit, FsCheck doesn't seem to be using the custom arbitrary Pattern to generate the test data. When I use LINQPad however everything works as expected. Here's the code:
open Xunit
open FsCheck
type Pattern = Pattern of string with
static member op_Explicit(Pattern s) = s
type MyArbitraries =
static member Pattern() =
(['a'..'c']#['?'; '*'])
|> Gen.elements
|> Gen.nonEmptyListOf
|> Gen.map (List.map string >> List.fold (+) "")
|> Arb.fromGen
|> Arb.convert Pattern string
Arb.register<MyArbitraries>() |> ignore
[<Fact>]
let test () =
let prop (Pattern p) = p.Length = 0
Check.QuickThrowOnFailure prop
This is the output:
Falsifiable, after 2 tests (0 shrinks) (StdGen (1884571966,296370531)): Original: Pattern null with exception: System.NullReferenceException ...
And here is the code I'm running in LINQPad along with the output:
open FsCheck
type Pattern = Pattern of string with
static member op_Explicit(Pattern s) = s
type MyArbitraries =
static member Pattern() =
(['a'..'c']#['?'; '*'])
|> Gen.elements
|> Gen.nonEmptyListOf
|> Gen.map (List.map string >> List.fold (+) "")
|> Arb.fromGen
|> Arb.convert Pattern string
Arb.register<MyArbitraries>() |> ignore
let prop (Pattern p) = p.Length = 0
Check.Quick prop
Falsifiable, after 1 test (0 shrinks) (StdGen (1148389153,296370531)): Original: Pattern "a*"
As you can see FsCheck generates a null value for the Pattern in the Xunit test although I'm using Gen.elements and Gen.nonEmptyListOf to control the test data. Also, when I run it a couple times, I'm seeing test patterns that are out of the specified character range. In LINQPad those patterns are generated correctly. I also tested the same with a regular F# console application in Visual Studio 2017 and there the custom Arbitrary works as expected as well.
What is going wrong? Is FsCheck falling back to the default string Arbitrary when running in Xunit?
You can clone this repo to see for yourself: https://github.com/bert2/GlobMatcher
(I don't want to use Prop.forAll, because each test will have multiple custom Arbitrarys and Prop.forAll doesn't go well with that. As far as I know I can only tuple them up, because the F# version of Prop.forAll only accepts a single Arbitrary.)
Don't use Arb.register. This method mutates global state, and due to the built-in parallelism support in xUnit.net 2, it's undetermined when it runs.
If you don't want to use the FsCheck.Xunit Glue Library, you can use Prop.forAll, which works like this:
[<Fact>]
let test () =
let prop (Pattern p) = p.Length = 0
Check.QuickThrowOnFailure (Prop.forAll (MyArbitraries.Pattern()) prop)
(I'm writing this partially from memory, so I may have made some small syntax mistakes, but hopefully, this should give you an idea on how to proceed.)
If, on the other hand, you choose to use FsCheck.Xunit, you can register your custom Arbitraries in a Property annotation, like this:
[<Property(Arbitrary = [|typeof<MyArbitraries>|])>]
let test (Pattern p) = p.Length = 0
As you can see, this takes care of much of the boilerplate; you don't even have to call Check.QuickThrowOnFailure.
The Arbitrary property takes an array of types, so when you have more than one, this still works.
If you need to write many properties with the same array of Arbitraries, you can create your own custom attributes that derives from the [<Property>] attribute. Here's an example:
type Letters =
static member Char() =
Arb.Default.Char()
|> Arb.filter (fun c -> 'A' <= c && c <= 'Z')
type DiamondPropertyAttribute() =
inherit PropertyAttribute(
Arbitrary = [| typeof<Letters> |],
QuietOnSuccess = true)
[<DiamondProperty>]
let ``Diamond is non-empty`` (letter : char) =
let actual = Diamond.make letter
not (String.IsNullOrWhiteSpace actual)
All that said, I'm not too fond of 'registering' Arbitraries like this. I much prefer using the combinator library, because it's type-safe, which this whole type-based mechanism isn't.

F#: shortest way to convert a string option to a string

The objective is to convert a string option that comes out of some nicely typed computation to a plain string that can then be passed to the UI/printf/URL/other things that just want a string and know nothing of option types. None should just become the empty string.
The obvious way is to do a match or an if on the input:
input |> fun s -> fun s -> match s with | Some v -> v | _ -> "" or
input |> fun s -> if s.IsSome then s.Value else ""
but while still being one-liners, these still take up quite a lot of line space. I was hoping to find the shortest possible method for doing this.
You can also use the function defaultArg input "" which in your code that uses forward pipe would be:
input |> fun s -> defaultArg s ""
Here's another way of writing the same but without the lambda:
input |> defaultArg <| ""
It would be better if we had a version in the F# core with the arguments flipped. Still I think this is the shortest way without relaying in other libraries or user defined functions.
UPDATE
Now in F# 4.1 FSharp.Core provides Option.defaultValue which is the same but with arguments flipped, so now you can simply write:
Option.defaultValue "" input
Which is pipe-forward friendly:
input |> Option.defaultValue ""
The obvious way is to write yourself a function to do it, and if you put it in an Option module, you won't even notice it's not part of the core library:
module Option =
let defaultTo defValue opt =
match opt with
| Some x -> x
| None -> defValue
Then use it like this:
input |> Option.defaultTo ""
The NuGet package FSharpX.Extras has Option.getOrElse which can be composed nicely.
let x = stringOption |> Option.getOrElse ""
The best solution I found so far is input |> Option.fold (+) "".
...which is just a shortened version of input |> Option.fold (fun s t -> s + t) "".
I suspect that it's the shortest I'll get, but I'd like to hear if there are other short ways of doing this that would be easier to understand by non-functional programmers.

How to traverse String[][] in F#

Context: Microsoft Visual Studio 2015 Community; F#
I've been learning F# for about 1/2 a day. I do have a vague idea of how to do functional programming from a year spent fiddling with mLite.
The following script traverses a folder tree and pulls in log files. The files have entries delimited by ~ and there may be one or more there.
open System
open System.IO
let files =
System.IO.Directory.GetFiles("C:\\scratch\\snapshots\\", "*.log", SearchOption.AllDirectories)
let readFile (file: string) =
//Console.WriteLine(file)
let text = File.ReadAllText(file)
text
let dataLines (line: string) =
line.Split('~')
let data =
files |> Array.map readFile |> Array.map dataLines
So at this point data contains a String[][] and I'm at a bit of a loss to figure out how to turn it into a String[], the idea being that I want to convert all the logs into one long vector so that I can do some other transformations on it. For example, each log line begins with a datetime so having turned it all into one long list I can then sort on the datetime.
Where to from here?
As stated in the comments, you can use Array.concat :
files |> Array.map readFile |> Array.map dataLines |> Array.concat
Now some refactoring, the composition of two maps is equivalent to the map of the composition of both functions.
files |> Array.map (readFile >> dataLines) |> Array.concat
Finally map >> concat is equivalent to collect. So your code becomes:
files |> Array.collect (readFile >> dataLines)

referencing one's own class library in a F# project on VS2015

i have a solution called Algos
on Solution explorer i have 2 projects inside this solution
one called Algos (again ! maybe i should change the name for avoiding confusion ?)
which is a console application
one called MyLibrary which is a Class Library
I have in the solution explorer added in the References of the Project Algo MyLibrary and i can see it in the list.
// useful functions
// returns the minimum + index of the minimum
namespace Misc
exception InnerError of string
module Search =
let mini (s : (int*int) list) =
match s with
| [] -> (-1,(-1,-1))
| _ -> s |> Seq.mapi (fun i x -> (i, x)) |> Seq.minBy snd
let maxi (s : (int*int) list) =
match s with
| [] -> (-1,(-1,-1))
| _ -> s |> Seq.mapi (fun i x -> (i, x)) |> Seq.maxBy snd
module Bit =
let rec sumbits (n:int):int=
let rec helper acc m =
match m with
| 0 -> acc
| 1 -> acc+1 // enlever cela ?
| _ -> let r = m%2
helper (acc+r) (m>>>1)
helper 0 n
let power2 k =
let powers_of_2 = [|1;2;4;8;16;32;64;128;256;512;1024;2048;4096;8192;16384;32768;65536;131072;262144;524288;1048576;2097152;4194304;8388608;16777216|]
if ((k >= 24) || (k<0)) then raise (InnerError("power exponent not allowed"))
else powers_of_2.[k]
i'm just to use Misc.Bit.power2 in the main code
open MyLibrary
let a = Misc.Bit.power2 3
but Misc.Bit will be underlined and I have a compiler error
Severity Code Description Project File Line Suppression State
Error The value, constructor, namespace or type 'Bit' is not defined Algos C:\Users\Fagui\Documents\GitHub\Learning Fsharp\Algos\Algos\TSP.fs 50
what have i done wrong ? does it come from other parts of the source code perhaps ?
there are no other warnings.
both projects use .NET Framework 4.5.2
MyLibrary uses Target F# Runtime 4.3.1 while there is no similar indication for Algos.
thanks
Two things come to mind here: I don't see where the namespace MyLibrary is defined, and you haven't mentioned that you actually compiled the dependency.
Generally, to reference and use a library within the same solution, you need to:
add the library to the using program's dependency, preferably via: References – right-click – add Reference (Reference Manager) – Projects – Solution, by checking the checkbox of the dependency.
compile the dependency. When referenced properly, this should automatically occur before dependent code is compiled, but IntelliSense will only update after compiles! So hit compile when you see outdated errors.
use identifiers from the library via their correct namespace. Make sure that the qualified names or open declarations in the using code are correct.
To my knowledge, this should be all you need to do.
There are rare cases where files get write-locked but never released on compilation and you need to restart Visual Studio to be able to compile again. I've also encountered a case where some interaction of Git and Visual Studio created corrupted, half-deleted files with effectively no file owner; this required a reboot to fix. If you're really scratching your head and the errors are clearly nonsensical, maybe try moving the folder to check for file system damage.
This should certainly work. Please also make sure that you target same versions of F# and .NET: .NET 4.5.2 and 4.4.0.0 in the library and the console application

F# RX Projection [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 11 years ago.
Want to convert some C# code for RX to F# code.
The following C# code works well:
var seqNum = Observable.Range(1, 5);
var seqString = from n in seqNum
select new string('*', (int)n);
seqString.Subscribe(str => { Console.WriteLine(str); });
Console.ReadKey();
The following is my code in F#:
#light
open System
open System.Collections.Generic
open System.Linq
open System.Reactive
open System.Reactive.Linq
open System.Reactive.Subjects
open System.Threading
open System.IO
let seqNum = Observable.Range(1, 5)
let seqString = from n in seqNum
select new string('*', (int)n)
Console.ReadLine() |> ignore
But I got the following compiler error:
Error: Unexpected keyword 'new' in implementation file
If I deleted the new keyword, I got another error:
Error: Successive arguments should be separated by spaces or tupled, and arguments involving function or method applications should be parenthesized
The "new" keyword are totally different in C# and F#.
Please show me how to do the same job in F#.
Thanks,
In C# string is the shortcut to System.String class. However, in F# string is a function which has obj as its input and returns a string which is overriden in obj.ToString():
let s = string('*', 3);; // tuple to string
// val s : string = "(*, 3)"
What you really want is creating a string by repeating '*' three times:
let s = new String('*', 3)
// val a : String = "***"
To be clear, from ... in ... select ... is C# LINQ syntax which is invalid in F#. Therefore, using computation expression instead:
let seqNum = seq {1..5}
let seqString = seq { for n in seqNum -> new String('*', n) }
To get some ideas of creating/using computation expression for Reactive Extension, take a look at the question and its answers at How do I change the Rx Builder implementation to fix the stack overflow exception?
Instead of using the String constructor use the String.replicate method.
String.replicate n "*"
There is no direct equivalent for String(char, int) but String.replicate: int -> string -> string is roughly the equivalent with string instead of char
F# version for that code
[1 .. 5]
|> Seq.map (fun i -> String.replicate i "*")
Here you go:
open System
open System.IO
open System.Reactive
open System.Reactive.Linq
let seqString = Observable.Range(1,5).Select(fun x -> String.replicate x "*")
using (seqString.Subscribe (fun x -> printfn "%s" x))
(fun _ -> Console.ReadLine() ) |> ignore
EDIT: As Paul suggested below two last lines can be replaced by simple
seqString.Subscribe (printfn "%s") |> ignore
However, if we want to gracefully unsubscribe from our subscription, but get rid of using in lieu of newer use syntax we may replace last two lines by the following three
do
use subscription = seqString.Subscribe(printfn "%s")
Console.ReadLine() |> ignore

Resources