Ben*_*jol 66 f# reference code-snippets
然而,我在这里寻找的是有用的片段,可重复使用的小"帮助"功能.或者模糊但又漂亮的模式,你永远不会记得.
就像是:
open System.IO
let rec visitor dir filter=
seq { yield! Directory.GetFiles(dir, filter)
for subdir in Directory.GetDirectories(dir) do
yield! visitor subdir filter}
Run Code Online (Sandbox Code Playgroud)
我想把它作为一个方便的参考页面.因此,没有正确的答案,但希望有很多好的答案.
EDIT Tomas Petricek专门为F#片段创建了一个网站http://fssnip.net/.
Jul*_*iet 27
Perl风格的正则表达式匹配
let (=~) input pattern =
System.Text.RegularExpressions.Regex.IsMatch(input, pattern)
Run Code Online (Sandbox Code Playgroud)
它允许您使用let test = "monkey" =~ "monk.+"符号匹配文本.
Kev*_*Won 27
中缀运营商
我从http://sandersn.com/blog//index.php/2009/10/22/infix-function-trick-for-f获得了这一点,请访问该页面了解更多详情.
如果您了解Haskell,您可能会发现自己在F#中缺少中缀糖:
// standard Haskell call has function first, then args just like F#. So obviously
// here there is a function that takes two strings: string -> string -> string
startsWith "kevin" "k"
//Haskell infix operator via backQuotes. Sometimes makes a function read better.
"kevin" `startsWith` "K"
Run Code Online (Sandbox Code Playgroud)
虽然F#没有真正的"中缀"运算符,但同样的事情可以通过管道和"反管道"(谁知道这样的事情)几乎同样优雅地完成.
// F# 'infix' trick via pipelines
"kevin" |> startsWith <| "K"
Run Code Online (Sandbox Code Playgroud)
Joe*_*ler 26
多行字符串
这非常简单,但它似乎是F#字符串的一个特征,并不为人所知.
let sql = "select a,b,c \
from table \
where a = 1"
Run Code Online (Sandbox Code Playgroud)
这会产生:
val sql : string = "select a,b,c from table where a = 1"
Run Code Online (Sandbox Code Playgroud)
当F#编译器看到一个反斜杠后跟一个字符串文字中的回车符时,它将删除从反斜杠到下一行的第一个非空格字符的所有内容.这允许您使用排成一行的多行字符串文字,而不使用一串字符串连接.
Ben*_*jol 24
通用备忘录,礼貌的男人自己
let memoize f =
let cache = System.Collections.Generic.Dictionary<_,_>(HashIdentity.Structural)
fun x ->
let ok, res = cache.TryGetValue(x)
if ok then res
else let res = f x
cache.[x] <- res
res
Run Code Online (Sandbox Code Playgroud)
使用这个,你可以这样做一个缓存的阅读器:
let cachedReader = memoize reader
Run Code Online (Sandbox Code Playgroud)
Ben*_*jol 18
对文本文件的简单读写
这些都是微不足道的,但是make file accessable:
open System.IO
let fileread f = File.ReadAllText(f)
let filewrite f s = File.WriteAllText(f, s)
let filereadlines f = File.ReadAllLines(f)
let filewritelines f ar = File.WriteAllLines(f, ar)
Run Code Online (Sandbox Code Playgroud)
所以
let replace f (r:string) (s:string) = s.Replace(f, r)
"C:\\Test.txt" |>
fileread |>
replace "teh" "the" |>
filewrite "C:\\Test.txt"
Run Code Online (Sandbox Code Playgroud)
并将其与问题中引用的访问者相结合:
let filereplace find repl path =
path |> fileread |> replace find repl |> filewrite path
let recurseReplace root filter find repl =
visitor root filter |> Seq.iter (filereplace find repl)
Run Code Online (Sandbox Code Playgroud)
如果您希望能够读取"锁定"文件(例如已在Excel中打开的csv文件...),则更新稍有改进:
let safereadall f =
use fs = new FileStream(f, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
use sr = new StreamReader(fs, System.Text.Encoding.Default)
sr.ReadToEnd()
let split sep (s:string) = System.Text.RegularExpressions.Regex.Split(s, sep)
let fileread f = safereadall f
let filereadlines f = f |> safereadall |> split System.Environment.NewLine
Run Code Online (Sandbox Code Playgroud)
thr*_*thr 17
对于性能密集型的东西,你需要检查null
let inline isNull o = System.Object.ReferenceEquals(o, null)
if isNull o then ... else ...
Run Code Online (Sandbox Code Playgroud)
比那时快20倍
if o = null then ... else ...
Run Code Online (Sandbox Code Playgroud)
Jam*_*ard 11
Active Patterns,又名"Banana Splits",是一个非常方便的结构,让人们可以匹配多个正则表达式模式.这很像AWK,但没有DFA的高性能,因为模式按顺序匹配,直到成功.
#light
open System
open System.Text.RegularExpressions
let (|Test|_|) pat s =
if (new Regex(pat)).IsMatch(s)
then Some()
else None
let (|Match|_|) pat s =
let opt = RegexOptions.None
let re = new Regex(pat,opt)
let m = re.Match(s)
if m.Success
then Some(m.Groups)
else None
Run Code Online (Sandbox Code Playgroud)
一些使用示例:
let HasIndefiniteArticle = function
| Test "(?: |^)(a|an)(?: |$)" _ -> true
| _ -> false
type Ast =
| IntVal of string * int
| StringVal of string * string
| LineNo of int
| Goto of int
let Parse = function
| Match "^LET\s+([A-Z])\s*=\s*(\d+)$" g ->
IntVal( g.[1].Value, Int32.Parse(g.[2].Value) )
| Match "^LET\s+([A-Z]\$)\s*=\s*(.*)$" g ->
StringVal( g.[1].Value, g.[2].Value )
| Match "^(\d+)\s*:$" g ->
LineNo( Int32.Parse(g.[1].Value) )
| Match "^GOTO \s*(\d+)$" g ->
Goto( Int32.Parse(g.[1].Value) )
| s -> failwithf "Unexpected statement: %s" s
Run Code Online (Sandbox Code Playgroud)
'Unitize'一个不处理单位
的FloatWithMeasure函数使用函数http://msdn.microsoft.com/en-us/library/ee806527(VS.100).aspx.
let unitize (f:float -> float) (v:float<'u>) =
LanguagePrimitives.FloatWithMeasure<'u> (f (float v))
Run Code Online (Sandbox Code Playgroud)
例:
[<Measure>] type m
[<Measure>] type kg
let unitize (f:float -> float) (v:float<'u>) =
LanguagePrimitives.FloatWithMeasure<'u> (f (float v))
//this function doesn't take units
let badinc a = a + 1.
//this one does!
let goodinc v = unitize badinc v
goodinc 3.<m>
goodinc 3.<kg>
Run Code Online (Sandbox Code Playgroud)
旧版本:
let unitize (f:float -> float) (v:float<'u>) =
let unit = box 1. :?> float<'u>
unit * (f (v/unit))
Run Code Online (Sandbox Code Playgroud)
荣誉给KVB
也许monad
type maybeBuilder() =
member this.Bind(v, f) =
match v with
| None -> None
| Some(x) -> f x
member this.Delay(f) = f()
member this.Return(v) = Some v
let maybe = maybeBuilder()
Run Code Online (Sandbox Code Playgroud)
这是一个简短的介绍,为不知情的monads.
选项合并运算符
我想要一个defaultArg语法更接近C#null-coalescing运算符的函数版本??.这使我可以使用非常简洁的语法从Option中获取值,同时提供默认值.
/// Option-coalescing operator - this is like the C# ?? operator, but works with
/// the Option type.
/// Warning: Unlike the C# ?? operator, the second parameter will always be
/// evaluated.
/// Example: let foo = someOption |? default
let inline (|?) value defaultValue =
defaultArg value defaultValue
/// Option-coalescing operator with delayed evaluation. The other version of
/// this operator always evaluates the default value expression. If you only
/// want to create the default value when needed, use this operator and pass
/// in a function that creates the default.
/// Example: let foo = someOption |?! (fun () -> new Default())
let inline (|?!) value f =
match value with Some x -> x | None -> f()
Run Code Online (Sandbox Code Playgroud)
比例/比率功能构建器
再次,琐碎,但方便.
//returns a function which will convert from a1-a2 range to b1-b2 range
let scale (a1:float<'u>, a2:float<'u>) (b1:float<'v>,b2:float<'v>) =
let m = (b2 - b1)/(a2 - a1) //gradient of line (evaluated once only..)
(fun a -> b1 + m * (a - a1))
Run Code Online (Sandbox Code Playgroud)
例:
[<Measure>] type m
[<Measure>] type px
let screenSize = (0.<px>, 300.<px>)
let displayRange = (100.<m>, 200.<m>)
let scaleToScreen = scale displayRange screenSize
scaleToScreen 120.<m> //-> 60.<px>
Run Code Online (Sandbox Code Playgroud)
转置列表(见Jomo Fisher的博客)
///Given list of 'rows', returns list of 'columns'
let rec transpose lst =
match lst with
| (_::_)::_ -> List.map List.head lst :: transpose (List.map List.tail lst)
| _ -> []
transpose [[1;2;3];[4;5;6];[7;8;9]] // returns [[1;4;7];[2;5;8];[3;6;9]]
Run Code Online (Sandbox Code Playgroud)
这是一个尾递归版本(从我粗略的分析)稍微慢一些,但是当内部列表超过10000个元素(在我的机器上)时,它具有不抛出堆栈溢出的优点:
let transposeTR lst =
let rec inner acc lst =
match lst with
| (_::_)::_ -> inner (List.map List.head lst :: acc) (List.map List.tail lst)
| _ -> List.rev acc
inner [] lst
Run Code Online (Sandbox Code Playgroud)
如果我很聪明,我会尝试将其与异步并行化......
(我知道,我知道,System.Collections.Generic.Dictionary并不是真正的'C#'字典)
C#到F#
(dic :> seq<_>) //cast to seq of KeyValuePair
|> Seq.map (|KeyValue|) //convert KeyValuePairs to tuples
|> Map.ofSeq //convert to Map
Run Code Online (Sandbox Code Playgroud)
(来自Brian,在这里,Mauricio在下面的评论中提出了改进.(|KeyValue|)是一个匹配KeyValuePair的活跃模式 - 来自FSharp.Core - 相当于(fun kvp -> kvp.Key, kvp.Value))
有趣的选择
要获得所有不可变的优点,但使用Dictionary的O(1)查找速度,您可以使用dict运算符,它返回一个不可变的IDictionary(请参阅此问题).
我目前看不到使用此方法直接转换Dictionary的方法,除了
(dic :> seq<_>) //cast to seq of KeyValuePair
|> (fun kvp -> kvp.Key, kvp.Value) //convert KeyValuePairs to tuples
|> dict //convert to immutable IDictionary
Run Code Online (Sandbox Code Playgroud)
F#到C#
let dic = Dictionary()
map |> Map.iter (fun k t -> dic.Add(k, t))
dic
Run Code Online (Sandbox Code Playgroud)
奇怪的是,FSI将报告类型(例如):
val it : Dictionary<string,int> = dict [("a",1);("b",2)]
Run Code Online (Sandbox Code Playgroud)
但如果你反馈dict [("a",1);("b",2)],FSI报道
IDictionary<string,int> = seq[[a,1] {Key = "a"; Value = 1; } ...
Run Code Online (Sandbox Code Playgroud)
树排序/将树平移到列表中
我有以下二叉树:
___ 77 _
/ \
______ 47 __ 99
/ \
21 _ 54
\ / \
43 53 74
/
39
/
32
Run Code Online (Sandbox Code Playgroud)
其代表如下:
type 'a tree =
| Node of 'a tree * 'a * 'a tree
| Nil
let myTree =
Node
(Node
(Node (Nil,21,Node (Node (Node (Nil,32,Nil),39,Nil),43,Nil)),47,
Node (Node (Nil,53,Nil),54,Node (Nil,74,Nil))),77,Node (Nil,99,Nil))
Run Code Online (Sandbox Code Playgroud)
压扁树的简单方法是:
let rec flatten = function
| Nil -> []
| Node(l, a, r) -> flatten l @ a::flatten r
Run Code Online (Sandbox Code Playgroud)
这不是尾递归的,我相信@运算符会使它为O(n log n)或O(n ^ 2),其中包含不平衡的二叉树.稍微调整一下,我想出了这个尾递归的O(n)版本:
let flatten2 t =
let rec loop acc c = function
| Nil -> c acc
| Node(l, a, r) ->
loop acc (fun acc' -> loop (a::acc') c l) r
loop [] (fun x -> x) t
Run Code Online (Sandbox Code Playgroud)
这是fsi中的输出:
> flatten2 myTree;;
val it : int list = [21; 32; 39; 43; 47; 53; 54; 74; 77; 99]
Run Code Online (Sandbox Code Playgroud)
LINQ-to-XML助手
namespace System.Xml.Linq
// hide warning about op_Explicit
#nowarn "77"
[<AutoOpen>]
module XmlUtils =
/// Converts a string to an XName.
let xn = XName.op_Implicit
/// Converts a string to an XNamespace.
let xmlns = XNamespace.op_Implicit
/// Gets the string value of any XObject subclass that has a Value property.
let inline xstr (x : ^a when ^a :> XObject) =
(^a : (member get_Value : unit -> string) x)
/// Gets a strongly-typed value from any XObject subclass, provided that
/// an explicit conversion to the output type has been defined.
/// (Many explicit conversions are defined on XElement and XAttribute)
/// Example: let value:int = xval foo
let inline xval (x : ^a when ^a :> XObject) : ^b =
((^a or ^b) : (static member op_Explicit : ^a -> ^b) x)
/// Dynamic lookup operator for getting an attribute value from an XElement.
/// Returns a string option, set to None if the attribute was not present.
/// Example: let value = foo?href
/// Example with default: let value = defaultArg foo?Name "<Unknown>"
let (?) (el:XElement) (name:string) =
match el.Attribute(xn name) with
| null -> None
| att -> Some(att.Value)
/// Dynamic operator for setting an attribute on an XElement.
/// Example: foo?href <- "http://www.foo.com/"
let (?<-) (el:XElement) (name:string) (value:obj) =
el.SetAttributeValue(xn name, value)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
11839 次 |
| 最近记录: |