F# snippets
Performance testing with Expecto
test "perf test" {
let seed = Random.mkStdGen 0L
let xs =
FsCheck.Arb.generate<'a> |> FsCheck.Gen.eval 1000 seed
Expect.isFasterThan (fun() -> optimizedFun xs |> ignore) (fun () -> originalFun xs |> ignore) ""
}
Memoize disposable
/// Memoize that invalidate cache of disposed object. Function checkF must be operation that crash on disposed object.
let memoizeDisposableBy (f: 'a -> 'b) (g: 'a -> 'c) checkF =
let cache = System.Collections.Concurrent.ConcurrentDictionary<_, _>(HashIdentity.Structural)
let rec get x =
let y = cache.GetOrAdd(Some (g x), lazy (f x)).Force()
try checkF y |> ignore; y
with :? ObjectDisposedException -> cache.TryRemove(Some (g x)) |> ignore; get x
get
Password encryption
Password encryption to be used in deploy scripts, so that we can safely share them.
#r "System.Security"
/// Generate random key and save it into "secretkey" file. This file serve as master key for password encryption, don't share it!
let initCrypto() =
let rng = new System.Security.Cryptography.RNGCryptoServiceProvider()
let entropy : byte[] = Array.zeroCreate 20
rng.GetBytes(entropy)
System.IO.File.WriteAllBytes("secretkey", entropy)
//initCrypto() // to be run once on target machine
/// Encrypt password, return string in Base64 format. This must be runned in same machine under same user as decrypt function.
let encrypt (x: string) =
let entropy = System.IO.File.ReadAllBytes("secretkey")
let bytes = System.Security.Cryptography.ProtectedData.Protect(System.Text.Encoding.ASCII.GetBytes x, entropy, System.Security.Cryptography.DataProtectionScope.CurrentUser)
bytes |> System.Convert.ToBase64String
/// Decrypt password from encrypted string in Base64 format.
let decrypt (x: string) =
let entropy = System.IO.File.ReadAllBytes("secretkey")
let bytes = x |> System.Convert.FromBase64String
let decryptedBytes = System.Security.Cryptography.ProtectedData.Unprotect(bytes, entropy, System.Security.Cryptography.DataProtectionScope.CurrentUser)
System.Text.Encoding.ASCII.GetString decryptedBytes
FsPickler
FsPickler can be used to "serialize" functions:
open MBrace.FsPickler
open MBrace.FsPickler.Json
let s = FsPickler.CreateJsonSerializer()
let pickle = s.PickleToString (fun x -> x + 1)
let f:int->int = bs.UnPickleOfString pickle
f(1)
Memoize recursive
let memoize (f: 'a -> 'b) =
let cache = System.Collections.Concurrent.ConcurrentDictionary<_, _>(HashIdentity.Structural)
fun x ->
cache.GetOrAdd(x, lazy (f x)).Force()
// This works, but emit warning: This and other recursive references to the object(s) being defined
// will be checked for initialization-soundness at runtime through the use of a delayed reference.
let rec fib' = memoize <| fun n -> if n<1 then 1 else fib' (n-1) + fib' (n-2)
let memoizeRec f =
let cache = System.Collections.Concurrent.ConcurrentDictionary<_, _>(HashIdentity.Structural)
let rec memF x =
cache.GetOrAdd(x, lazy (f memF x)).Force()
memF
let fib = memoizeRec <| fun f n -> if n<1 then 1 else f (n-1) + f (n-2)
Memoize
let memoizeBy (f: 'a -> 'b) (g: 'a -> 'c) =
let cache = System.Collections.Concurrent.ConcurrentDictionary<_, _>(HashIdentity.Structural)
fun x ->
cache.GetOrAdd(Some (g x), lazy (f x)).Force()
let inline memoize f = memoizeBy f id
let inline memoizeConst f =
let g = memoize (fun _ -> f())
fun () -> g 0