From 0b2de0c52dec5954a8d3330beebd8b5cae35981d Mon Sep 17 00:00:00 2001 From: Endericedragon Fu Date: Tue, 26 Aug 2025 11:08:36 +0800 Subject: [PATCH 1/9] Start translating F# into Chinese(zh-cn)! --- zh-cn/fsharp.md | 651 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 651 insertions(+) create mode 100644 zh-cn/fsharp.md diff --git a/zh-cn/fsharp.md b/zh-cn/fsharp.md new file mode 100644 index 0000000000..85e6e1a336 --- /dev/null +++ b/zh-cn/fsharp.md @@ -0,0 +1,651 @@ +--- +name: F# +contributors: + - ["Scott Wlaschin", "http://fsharpforfunandprofit.com/"] +filename: learnfsharp.fs +--- + +F# is a general purpose functional/OO programming language. It's free and open source, and runs on Linux, Mac, Windows and more. + +It has a powerful type system that traps many errors at compile time, but it uses type inference so that it reads more like a dynamic language. + +The syntax of F# is different from C-style languages: + +* Curly braces are not used to delimit blocks of code. Instead, indentation is used (like Python). +* Whitespace is used to separate parameters rather than commas. + +If you want to try out the code below, you can go to [https://try.fsharp.org](https://try.fsharp.org) and paste it into an interactive REPL. + +```fsharp +// single line comments use a double slash +(* multi line comments use (* . . . *) pair + +-end of multi line comment- *) + +// ================================================ +// Basic Syntax +// ================================================ + +// ------ "Variables" (but not really) ------ +// The "let" keyword defines an (immutable) value +let myInt = 5 +let myFloat = 3.14 +let myString = "hello" // note that no types needed + +// Mutable variables +let mutable a=3 +a <- 4 // a is now 4. + +// Somewhat mutable variables +// Reference cells are storage locations that enable you to create mutable values with reference semantics. +// See https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/reference-cells +let xRef = ref 10 +printfn "%d" xRef.Value // 10 +xRef.Value <- 11 +printfn "%d" xRef.Value // 11 + +let a=[ref 0; ref 1] // somewhat mutable list +a[0].Value <- 2 + +// ------ Lists ------ +let twoToFive = [2; 3; 4; 5] // Square brackets create a list with + // semicolon delimiters. +let oneToFive = 1 :: twoToFive // :: creates list with new 1st element +// The result is [1; 2; 3; 4; 5] +let zeroToFive = [0; 1] @ twoToFive // @ concats two lists + +// IMPORTANT: commas are never used as delimiters, only semicolons! + +// ------ Functions ------ +// The "let" keyword also defines a named function. +let square x = x * x // Note that no parens are used. +square 3 // Now run the function. Again, no parens. + +let add x y = x + y // don't use add (x,y)! It means something + // completely different. +add 2 3 // Now run the function. + +// to define a multiline function, just use indents. No semicolons needed. +let evens list = + let isEven x = x % 2 = 0 // Define "isEven" as a sub function. Note + // that equality operator is single char "=". + List.filter isEven list // List.filter is a library function + // with two parameters: a boolean function + // and a list to work on + +evens oneToFive // Now run the function + +// You can use parens to clarify precedence. In this example, +// do "map" first, with two args, then do "sum" on the result. +// Without the parens, "List.map" would be passed as an arg to List.sum +let sumOfSquaresTo100 = + List.sum ( List.map square [1..100] ) + +// You can pipe the output of one operation to the next using "|>" +// Piping data around is very common in F#, similar to UNIX pipes. + +// Here is the same sumOfSquares function written using pipes +let sumOfSquaresTo100piped = + [1..100] |> List.map square |> List.sum // "square" was defined earlier + +// you can define lambdas (anonymous functions) using the "fun" keyword +let sumOfSquaresTo100withFun = + [1..100] |> List.map (fun x -> x * x) |> List.sum + +// In F# there is no "return" keyword. A function always +// returns the value of the last expression used. + +// ------ Pattern Matching ------ +// Match..with.. is a supercharged case/switch statement. +let simplePatternMatch = + let x = "a" + match x with + | "a" -> printfn "x is a" + | "b" -> printfn "x is b" + | _ -> printfn "x is something else" // underscore matches anything + +// F# doesn't allow nulls by default -- you must use an Option type +// and then pattern match. +// Some(..) and None are roughly analogous to Nullable wrappers +let validValue = Some(99) +let invalidValue = None + +// In this example, match..with matches the "Some" and the "None", +// and also unpacks the value in the "Some" at the same time. +let optionPatternMatch input = + match input with + | Some i -> printfn "input is an int=%d" i + | None -> printfn "input is missing" + +optionPatternMatch validValue +optionPatternMatch invalidValue + +// ------ Printing ------ +// The printf/printfn functions are similar to the +// Console.Write/WriteLine functions in C#. +printfn "Printing an int %i, a float %f, a bool %b" 1 2.0 true +printfn "A string %s, and something generic %A" "hello" [1; 2; 3; 4] + +// There are also sprintf/sprintfn functions for formatting data +// into a string, similar to String.Format in C#. + +// ================================================ +// More on functions +// ================================================ + +// F# is a true functional language -- functions are first +// class entities and can be combined easily to make powerful +// constructs + +// Modules are used to group functions together +// Indentation is needed for each nested module. +module FunctionExamples = + + // define a simple adding function + let add x y = x + y + + // basic usage of a function + let a = add 1 2 + printfn "1 + 2 = %i" a + + // partial application to "bake in" parameters + let add42 = add 42 + let b = add42 1 + printfn "42 + 1 = %i" b + + // composition to combine functions + let add1 = add 1 + let add2 = add 2 + let add3 = add1 >> add2 + let c = add3 7 + printfn "3 + 7 = %i" c + + // higher order functions + [1..10] |> List.map add3 |> printfn "new list is %A" + + // lists of functions, and more + let add6 = [add1; add2; add3] |> List.reduce (>>) + let d = add6 7 + printfn "1 + 2 + 3 + 7 = %i" d + +// ================================================ +// Lists and collection +// ================================================ + +// There are three types of ordered collection: +// * Lists are most basic immutable collection. +// * Arrays are mutable and more efficient when needed. +// * Sequences are lazy and infinite (e.g. an enumerator). +// +// Other collections include immutable maps and sets +// plus all the standard .NET collections + +module ListExamples = + + // lists use square brackets + let list1 = ["a"; "b"] + let list2 = "c" :: list1 // :: is prepending + let list3 = list1 @ list2 // @ is concat + + // list comprehensions (aka generators) + let squares = [for i in 1..10 do yield i * i] + + // A prime number generator + // - this is using a short notation for the pattern matching syntax + // - (p::xs) is 'first :: tail' of the list, could also be written as p :: xs + // this means this matches 'p' (the first item in the list), and xs is the rest of the list + // this is called the 'cons pattern' + // - uses 'rec' keyword, which is necessary when using recursion + let rec sieve = function + | (p::xs) -> p :: sieve [ for x in xs do if x % p > 0 then yield x ] + | [] -> [] + let primes = sieve [2..50] + printfn "%A" primes + + // pattern matching for lists + let listMatcher aList = + match aList with + | [] -> printfn "the list is empty" + | [first] -> printfn "the list has one element %A " first + | [first; second] -> printfn "list is %A and %A" first second + | first :: _ -> printfn "the list has more than two elements, first element %A" first + + listMatcher [1; 2; 3; 4] + listMatcher [1; 2] + listMatcher [1] + listMatcher [] + + // recursion using lists + let rec sum aList = + match aList with + | [] -> 0 + | x::xs -> x + sum xs + sum [1..10] + + // ----------------------------------------- + // Standard library functions + // ----------------------------------------- + + // map + let add3 x = x + 3 + [1..10] |> List.map add3 + + // filter + let even x = x % 2 = 0 + [1..10] |> List.filter even + + // many more -- see documentation + +module ArrayExamples = + + // arrays use square brackets with bar + let array1 = [| "a"; "b" |] + let first = array1.[0] // indexed access using dot + + // pattern matching for arrays is same as for lists + let arrayMatcher aList = + match aList with + | [| |] -> printfn "the array is empty" + | [| first |] -> printfn "the array has one element %A " first + | [| first; second |] -> printfn "array is %A and %A" first second + | _ -> printfn "the array has more than two elements" + + arrayMatcher [| 1; 2; 3; 4 |] + + // Standard library functions just as for List + + [| 1..10 |] + |> Array.map (fun i -> i + 3) + |> Array.filter (fun i -> i % 2 = 0) + |> Array.iter (printfn "value is %i. ") + + +module SequenceExamples = + + // sequences use curly braces + let seq1 = seq { yield "a"; yield "b" } + + // sequences can use yield and + // can contain subsequences + let strange = seq { + // "yield" adds one element + yield 1; yield 2; + + // "yield!" adds a whole subsequence + yield! [5..10] + yield! seq { + for i in 1..10 do + if i % 2 = 0 then yield i }} + // test + strange |> Seq.toList + + + // Sequences can be created using "unfold" + // Here's the fibonacci series + let fib = Seq.unfold (fun (fst,snd) -> + Some(fst + snd, (snd, fst + snd))) (0,1) + + // test + let fib10 = fib |> Seq.take 10 |> Seq.toList + printf "first 10 fibs are %A" fib10 + + +// ================================================ +// Data Types +// ================================================ + +module DataTypeExamples = + + // All data is immutable by default + + // Tuples are quick 'n easy anonymous types + // -- Use a comma to create a tuple + let twoTuple = 1, 2 + let threeTuple = "a", 2, true + + // Pattern match to unpack + let x, y = twoTuple // sets x = 1, y = 2 + + // ------------------------------------ + // Record types have named fields + // ------------------------------------ + + // Use "type" with curly braces to define a record type + type Person = {First:string; Last:string} + + // Use "let" with curly braces to create a record + let person1 = {First="John"; Last="Doe"} + + // Pattern match to unpack + let {First = first} = person1 // sets first="John" + + // ------------------------------------ + // Union types (aka variants) have a set of choices + // Only one case can be valid at a time. + // ------------------------------------ + + // Use "type" with bar/pipe to define a union type + type Temp = + | DegreesC of float + | DegreesF of float + + // Use one of the cases to create one + let temp1 = DegreesF 98.6 + let temp2 = DegreesC 37.0 + + // Pattern match on all cases to unpack + let printTemp = function + | DegreesC t -> printfn "%f degC" t + | DegreesF t -> printfn "%f degF" t + + printTemp temp1 + printTemp temp2 + + // ------------------------------------ + // Recursive types + // ------------------------------------ + + // Types can be combined recursively in complex ways + // without having to create subclasses + type Employee = + | Worker of Person + | Manager of Employee list + + let jdoe = {First="John"; Last="Doe"} + let worker = Worker jdoe + + // ------------------------------------ + // Modeling with types + // ------------------------------------ + + // Union types are great for modeling state without using flags + type EmailAddress = + | ValidEmailAddress of string + | InvalidEmailAddress of string + + let trySendEmail email = + match email with // use pattern matching + | ValidEmailAddress address -> () // send + | InvalidEmailAddress address -> () // don't send + + // The combination of union types and record types together + // provide a great foundation for domain driven design. + // You can create hundreds of little types that accurately + // reflect the domain. + + type CartItem = { ProductCode: string; Qty: int } + type Payment = Payment of float + type ActiveCartData = { UnpaidItems: CartItem list } + type PaidCartData = { PaidItems: CartItem list; Payment: Payment} + + type ShoppingCart = + | EmptyCart // no data + | ActiveCart of ActiveCartData + | PaidCart of PaidCartData + + // ------------------------------------ + // Built in behavior for types + // ------------------------------------ + + // Core types have useful "out-of-the-box" behavior, no coding needed. + // * Immutability + // * Pretty printing when debugging + // * Equality and comparison + // * Serialization + + // Pretty printing using %A + printfn "twoTuple=%A,\nPerson=%A,\nTemp=%A,\nEmployee=%A" + twoTuple person1 temp1 worker + + // Equality and comparison built in. + // Here's an example with cards. + type Suit = Club | Diamond | Spade | Heart + type Rank = Two | Three | Four | Five | Six | Seven | Eight + | Nine | Ten | Jack | Queen | King | Ace + + let hand = [ Club, Ace; Heart, Three; Heart, Ace; + Spade, Jack; Diamond, Two; Diamond, Ace ] + + // sorting + List.sort hand |> printfn "sorted hand is (low to high) %A" + List.max hand |> printfn "high card is %A" + List.min hand |> printfn "low card is %A" + + +// ================================================ +// Active patterns +// ================================================ + +module ActivePatternExamples = + + // F# has a special type of pattern matching called "active patterns" + // where the pattern can be parsed or detected dynamically. + + // "banana clips" are the syntax for active patterns + + // You can use "elif" instead of "else if" in conditional expressions. + // They are equivalent in F# + + // for example, define an "active" pattern to match character types... + let (|Digit|Letter|Whitespace|Other|) ch = + if System.Char.IsDigit(ch) then Digit + elif System.Char.IsLetter(ch) then Letter + elif System.Char.IsWhiteSpace(ch) then Whitespace + else Other + + // ... and then use it to make parsing logic much clearer + let printChar ch = + match ch with + | Digit -> printfn "%c is a Digit" ch + | Letter -> printfn "%c is a Letter" ch + | Whitespace -> printfn "%c is a Whitespace" ch + | _ -> printfn "%c is something else" ch + + // print a list + ['a'; 'b'; '1'; ' '; '-'; 'c'] |> List.iter printChar + + // ----------------------------------- + // FizzBuzz using active patterns + // ----------------------------------- + + // You can create partial matching patterns as well + // Just use underscore in the definition, and return Some if matched. + let (|MultOf3|_|) i = if i % 3 = 0 then Some MultOf3 else None + let (|MultOf5|_|) i = if i % 5 = 0 then Some MultOf5 else None + + // the main function + let fizzBuzz i = + match i with + | MultOf3 & MultOf5 -> printf "FizzBuzz, " + | MultOf3 -> printf "Fizz, " + | MultOf5 -> printf "Buzz, " + | _ -> printf "%i, " i + + // test + [1..20] |> List.iter fizzBuzz + +// ================================================ +// Conciseness +// ================================================ + +module AlgorithmExamples = + + // F# has a high signal/noise ratio, so code reads + // almost like the actual algorithm + + // ------ Example: define sumOfSquares function ------ + let sumOfSquares n = + [1..n] // 1) take all the numbers from 1 to n + |> List.map square // 2) square each one + |> List.sum // 3) sum the results + + // test + sumOfSquares 100 |> printfn "Sum of squares = %A" + + // ------ Example: define a sort function ------ + let rec sort list = + match list with + // If the list is empty + | [] -> + [] // return an empty list + // If the list is not empty + | firstElem::otherElements -> // take the first element + let smallerElements = // extract the smaller elements + otherElements // from the remaining ones + |> List.filter (fun e -> e < firstElem) + |> sort // and sort them + let largerElements = // extract the larger ones + otherElements // from the remaining ones + |> List.filter (fun e -> e >= firstElem) + |> sort // and sort them + // Combine the 3 parts into a new list and return it + List.concat [smallerElements; [firstElem]; largerElements] + + // test + sort [1; 5; 23; 18; 9; 1; 3] |> printfn "Sorted = %A" + +// ================================================ +// Asynchronous Code +// ================================================ + +module AsyncExample = + + // F# has built-in features to help with async code + // without encountering the "pyramid of doom" + // + // The following example downloads a set of web pages in parallel. + + open System.Net + open System + open System.IO + open Microsoft.FSharp.Control.CommonExtensions + + // Fetch the contents of a URL asynchronously + let fetchUrlAsync url = + async { // "async" keyword and curly braces + // creates an "async" object + let req = WebRequest.Create(Uri(url)) + use! resp = req.AsyncGetResponse() + // use! is async assignment + use stream = resp.GetResponseStream() + // "use" triggers automatic close() + // on resource at end of scope + use reader = new IO.StreamReader(stream) + let html = reader.ReadToEnd() + printfn "finished downloading %s" url + } + + // a list of sites to fetch + let sites = ["http://www.bing.com"; + "http://www.google.com"; + "http://www.microsoft.com"; + "http://www.amazon.com"; + "http://www.yahoo.com"] + + // do it + sites + |> List.map fetchUrlAsync // make a list of async tasks + |> Async.Parallel // set up the tasks to run in parallel + |> Async.RunSynchronously // start them off + +// ================================================ +// .NET compatibility +// ================================================ + +module NetCompatibilityExamples = + + // F# can do almost everything C# can do, and it integrates + // seamlessly with .NET or Mono libraries. + + // ------- work with existing library functions ------- + + let (i1success, i1) = System.Int32.TryParse("123"); + if i1success then printfn "parsed as %i" i1 else printfn "parse failed" + + // ------- Implement interfaces on the fly! ------- + + // create a new object that implements IDisposable + let makeResource name = + { new System.IDisposable + with member this.Dispose() = printfn "%s disposed" name } + + let useAndDisposeResources = + use r1 = makeResource "first resource" + printfn "using first resource" + for i in [1..3] do + let resourceName = sprintf "\tinner resource %d" i + use temp = makeResource resourceName + printfn "\tdo something with %s" resourceName + use r2 = makeResource "second resource" + printfn "using second resource" + printfn "done." + + // ------- Object oriented code ------- + + // F# is also a fully fledged OO language. + // It supports classes, inheritance, virtual methods, etc. + + // interface with generic type + type IEnumerator<'a> = + abstract member Current : 'a + abstract MoveNext : unit -> bool + + // abstract base class with virtual methods + [] + type Shape() = + // readonly properties + abstract member Width : int with get + abstract member Height : int with get + // non-virtual method + member this.BoundingArea = this.Height * this.Width + // virtual method with base implementation + abstract member Print : unit -> unit + default this.Print () = printfn "I'm a shape" + + // concrete class that inherits from base class and overrides + type Rectangle(x:int, y:int) = + inherit Shape() + override this.Width = x + override this.Height = y + override this.Print () = printfn "I'm a Rectangle" + + // test + let r = Rectangle(2, 3) + printfn "The width is %i" r.Width + printfn "The area is %i" r.BoundingArea + r.Print() + + // ------- extension methods ------- + + // Just as in C#, F# can extend existing classes with extension methods. + type System.String with + member this.StartsWithA = this.StartsWith "A" + + // test + let s = "Alice" + printfn "'%s' starts with an 'A' = %A" s s.StartsWithA + + // ------- events ------- + + type MyButton() = + let clickEvent = new Event<_>() + + [] + member this.OnClick = clickEvent.Publish + + member this.TestEvent(arg) = + clickEvent.Trigger(this, arg) + + // test + let myButton = new MyButton() + myButton.OnClick.Add(fun (sender, arg) -> + printfn "Click event with arg=%O" arg) + + myButton.TestEvent("Hello World!") +``` + +## More Information + +For more demonstrations of F#, go to my [why use F#](http://fsharpforfunandprofit.com/why-use-fsharp/) series. + +Read more about F# at [fsharp.org](http://fsharp.org/) and [dotnet's F# page](https://dotnet.microsoft.com/languages/fsharp). From 5b50e0828f40bd598f01fdf174b152dee3f6d260 Mon Sep 17 00:00:00 2001 From: Endericedragon Fu Date: Tue, 26 Aug 2025 11:29:05 +0800 Subject: [PATCH 2/9] Completed translation before 'Lists' --- zh-cn/fsharp.md | 55 +++++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/zh-cn/fsharp.md b/zh-cn/fsharp.md index 85e6e1a336..b011762958 100644 --- a/zh-cn/fsharp.md +++ b/zh-cn/fsharp.md @@ -2,59 +2,60 @@ name: F# contributors: - ["Scott Wlaschin", "http://fsharpforfunandprofit.com/"] +translators: + - ["Endericedragon", "http://github.com/endericedragon"] filename: learnfsharp.fs --- -F# is a general purpose functional/OO programming language. It's free and open source, and runs on Linux, Mac, Windows and more. +F# 是一款通用的、函数式的面向对象语言。它既开源又免费,并且在Linux、Mac和Windows等多平台上均可运行。 -It has a powerful type system that traps many errors at compile time, but it uses type inference so that it reads more like a dynamic language. +这款语言拥有强大的类型系统,许多错误在编译器即可被发现并随之被修复。不过,由于 F# 采用了类型推理技术(译者注:不需手动指定,而是通过上下文自动推断变量的类型),在读代码时往往给人一种动态类型语言的错觉。 -The syntax of F# is different from C-style languages: +需要留意的是, F# 的语法和“类C语言”有较大不同: +- 使用**缩进**来组织代码块(类似Python那样),而不是大括号。 +- 使用**空格**来分隔函数的各个参数,而不是逗号。 -* Curly braces are not used to delimit blocks of code. Instead, indentation is used (like Python). -* Whitespace is used to separate parameters rather than commas. - -If you want to try out the code below, you can go to [https://try.fsharp.org](https://try.fsharp.org) and paste it into an interactive REPL. +若您想尝试运行以下代码,看看效果如何的话,请移步[https://try.fsharp.org](https://try.fsharp.org),将代码粘贴进交互式REPL界面运行吧。 ```fsharp -// single line comments use a double slash -(* multi line comments use (* . . . *) pair - --end of multi line comment- *) +// 单行注释以双斜杠开头 +(* 多行注释以包裹在 (* , *) 之间 +多行注释至此结束- *) // ================================================ -// Basic Syntax +// 基础语法 // ================================================ -// ------ "Variables" (but not really) ------ -// The "let" keyword defines an (immutable) value +// ------ "变量" (实际上默认不可变) ------ +// "let" 关键字可定义一个(不可变的)变量 let myInt = 5 let myFloat = 3.14 -let myString = "hello" // note that no types needed +let myString = "hello" // 注意到并不需要指定类型 -// Mutable variables +// 可变变量 let mutable a=3 -a <- 4 // a is now 4. +a <- 4 // a现在的值是4 -// Somewhat mutable variables -// Reference cells are storage locations that enable you to create mutable values with reference semantics. -// See https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/reference-cells +// 稍有不同的可变变量 +// Reference cell是一种容器,允许您使用引用语义来创建可变变量(create mutable values with reference semantics) +// 译者注:和Rust的RefCell类似,提供容器内部的可变性 +// 详见 https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/reference-cells let xRef = ref 10 printfn "%d" xRef.Value // 10 xRef.Value <- 11 printfn "%d" xRef.Value // 11 -let a=[ref 0; ref 1] // somewhat mutable list +let a = [ref 0; ref 1] // 装有可变元素的数组 a[0].Value <- 2 -// ------ Lists ------ -let twoToFive = [2; 3; 4; 5] // Square brackets create a list with - // semicolon delimiters. -let oneToFive = 1 :: twoToFive // :: creates list with new 1st element +// ------ 列表Lists ------ +let twoToFive = [2; 3; 4; 5] // 使用方括号创建列表 + // 元素间使用**分号**分隔 +let oneToFive = 1 :: twoToFive // :: 创建新列表,并将新元素添加到开头 // The result is [1; 2; 3; 4; 5] -let zeroToFive = [0; 1] @ twoToFive // @ concats two lists +let zeroToFive = [0; 1] @ twoToFive // @ 可合并两个列表 -// IMPORTANT: commas are never used as delimiters, only semicolons! +// 重要提示:是使用分号来分隔语句,而不是逗号!! // ------ Functions ------ // The "let" keyword also defines a named function. From b34deaa874f1b28c424241dfab64e71f79e6fcc5 Mon Sep 17 00:00:00 2001 From: Endericedragon Fu Date: Tue, 26 Aug 2025 16:53:19 +0800 Subject: [PATCH 3/9] Completed translatioin before "Pattern Matching" --- zh-cn/fsharp.md | 64 +++++++++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/zh-cn/fsharp.md b/zh-cn/fsharp.md index b011762958..e425e49b97 100644 --- a/zh-cn/fsharp.md +++ b/zh-cn/fsharp.md @@ -30,9 +30,9 @@ F# 是一款通用的、函数式的面向对象语言。它既开源又免费 // "let" 关键字可定义一个(不可变的)变量 let myInt = 5 let myFloat = 3.14 -let myString = "hello" // 注意到并不需要指定类型 +let myString = "hello" // 注意,并不需要指定类型 -// 可变变量 +// 可变变量用 "mutable" 标注 let mutable a=3 a <- 4 // a现在的值是4 @@ -57,44 +57,46 @@ let zeroToFive = [0; 1] @ twoToFive // @ 可合并两个列表 // 重要提示:是使用分号来分隔语句,而不是逗号!! -// ------ Functions ------ -// The "let" keyword also defines a named function. -let square x = x * x // Note that no parens are used. -square 3 // Now run the function. Again, no parens. +// ------ 函数 ------ +// "let" 关键字也可以用来定义函数 +let square x = x * x // 注意,没有使用圆括号 +square 3 // 注意,运行函数时也不需要圆括号 -let add x y = x + y // don't use add (x,y)! It means something - // completely different. -add 2 3 // Now run the function. +let add x y = x + y // 切勿将参数写成 (x, y)! + // 这是元组Tuple的写法(稍后介绍), + // 和函数参数完全不同 +add 2 3 // 调用该函数 -// to define a multiline function, just use indents. No semicolons needed. +// 使用缩进来定义一个多行的复杂函数。不需要写分号 let evens list = - let isEven x = x % 2 = 0 // Define "isEven" as a sub function. Note - // that equality operator is single char "=". - List.filter isEven list // List.filter is a library function - // with two parameters: a boolean function - // and a list to work on + let isEven x = x % 2 = 0 // 定义**子函数** "isEven"。 + // 注意“相等”是使用单等号'='而不是双等号"==" + List.filter isEven list // List.filter 是个 F# 库函数,它有两个参数: + // - 返回值为boolean的函数 + // - 待处理的列表 -evens oneToFive // Now run the function +evens oneToFive // 调用该函数 + +// 圆括号可用于显式地标注计算优先级。在下述示例代码中: +// 1. 首先进行 List.map 计算,该函数具有两个参数 +// 2. 然后进行 List.sum 计算,将上一步的结果作为该步的参数 +// 若不写圆括号,"List.map" 就会被当作参数传递给 List.sum -// You can use parens to clarify precedence. In this example, -// do "map" first, with two args, then do "sum" on the result. -// Without the parens, "List.map" would be passed as an arg to List.sum let sumOfSquaresTo100 = List.sum ( List.map square [1..100] ) -// You can pipe the output of one operation to the next using "|>" -// Piping data around is very common in F#, similar to UNIX pipes. +// 使用管道操作符 "|>" ,可以将上一步的输出(译者注:即返回值)输送给下一步作为输入 +// 管道操作在 F# 中很常见,其语义也与 UNIX 操作系统中的管道操作非常相似。 -// Here is the same sumOfSquares function written using pipes +// 使用管道操作符,可将 sumOfSquares 函数重构为如下形式: let sumOfSquaresTo100piped = - [1..100] |> List.map square |> List.sum // "square" was defined earlier + [1..100] |> List.map square |> List.sum // "square" 函数就是之前定义的,求平方的函数 -// you can define lambdas (anonymous functions) using the "fun" keyword +// 匿名函数(或作lambda函数)可用 "fun" 关键字定义 let sumOfSquaresTo100withFun = [1..100] |> List.map (fun x -> x * x) |> List.sum -// In F# there is no "return" keyword. A function always -// returns the value of the last expression used. +// F# 中没有"return" 关键字,因为函数总是返回最后一个表达式的值。 // ------ Pattern Matching ------ // Match..with.. is a supercharged case/switch statement. @@ -626,7 +628,7 @@ module NetCompatibilityExamples = let s = "Alice" printfn "'%s' starts with an 'A' = %A" s s.StartsWithA - // ------- events ------- + // ------- 事件 ------- type MyButton() = let clickEvent = new Event<_>() @@ -637,7 +639,7 @@ module NetCompatibilityExamples = member this.TestEvent(arg) = clickEvent.Trigger(this, arg) - // test + // 测试效果 let myButton = new MyButton() myButton.OnClick.Add(fun (sender, arg) -> printfn "Click event with arg=%O" arg) @@ -645,8 +647,8 @@ module NetCompatibilityExamples = myButton.TestEvent("Hello World!") ``` -## More Information +## 更多信息 -For more demonstrations of F#, go to my [why use F#](http://fsharpforfunandprofit.com/why-use-fsharp/) series. +欲参阅更多 F# 示例代码,请移步 [why use F#](http://fsharpforfunandprofit.com/why-use-fsharp/) 系列文章。 -Read more about F# at [fsharp.org](http://fsharp.org/) and [dotnet's F# page](https://dotnet.microsoft.com/languages/fsharp). +欲更深入了解 F# ,请移步 [fsharp.org](http://fsharp.org/) 与 [dotnet's F# page](https://dotnet.microsoft.com/languages/fsharp)。 From cf06920f1be86bebe86b464e08d438079069753e Mon Sep 17 00:00:00 2001 From: Endericedragon Fu Date: Tue, 26 Aug 2025 22:56:58 +0800 Subject: [PATCH 4/9] Completed part of Modules --- zh-cn/fsharp.md | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/zh-cn/fsharp.md b/zh-cn/fsharp.md index e425e49b97..03fd5c40ee 100644 --- a/zh-cn/fsharp.md +++ b/zh-cn/fsharp.md @@ -52,7 +52,7 @@ a[0].Value <- 2 let twoToFive = [2; 3; 4; 5] // 使用方括号创建列表 // 元素间使用**分号**分隔 let oneToFive = 1 :: twoToFive // :: 创建新列表,并将新元素添加到开头 -// The result is [1; 2; 3; 4; 5] +// 结果为 [1; 2; 3; 4; 5] let zeroToFive = [0; 1] @ twoToFive // @ 可合并两个列表 // 重要提示:是使用分号来分隔语句,而不是逗号!! @@ -98,23 +98,22 @@ let sumOfSquaresTo100withFun = // F# 中没有"return" 关键字,因为函数总是返回最后一个表达式的值。 -// ------ Pattern Matching ------ -// Match..with.. is a supercharged case/switch statement. +// ------ 模式匹配 ------ +// 模式匹配 match..with.. 是个加强版的 case/switch let simplePatternMatch = let x = "a" match x with | "a" -> printfn "x is a" | "b" -> printfn "x is b" - | _ -> printfn "x is something else" // underscore matches anything + | _ -> printfn "x is something else" // 下划线可匹配任意值 -// F# doesn't allow nulls by default -- you must use an Option type -// and then pattern match. -// Some(..) and None are roughly analogous to Nullable wrappers +// F# 默认不支持空值(null),您必须使用Option类型以便随后进行模式匹配 +// Some(..) 和 None 均为Option类型的一种,用于表示"可能为空值"的两种情况 let validValue = Some(99) let invalidValue = None -// In this example, match..with matches the "Some" and the "None", -// and also unpacks the value in the "Some" at the same time. +// 在下列示例中,match..with 不仅匹配了 "Some" 和 "None" 两种情况, +// 还同时将 "Some" 中的内容给解包出来了 let optionPatternMatch input = match input with | Some i -> printfn "input is an int=%d" i @@ -123,22 +122,19 @@ let optionPatternMatch input = optionPatternMatch validValue optionPatternMatch invalidValue -// ------ Printing ------ -// The printf/printfn functions are similar to the -// Console.Write/WriteLine functions in C#. +// ------ 打印内容 ------ +// printf/printfn 函数与 C# 中的 Console.Write/WriteLine 函数类似 printfn "Printing an int %i, a float %f, a bool %b" 1 2.0 true printfn "A string %s, and something generic %A" "hello" [1; 2; 3; 4] -// There are also sprintf/sprintfn functions for formatting data -// into a string, similar to String.Format in C#. +// 若要按一定格式生成字符串,可以使用 sprintf/sprintfn 函数, +// 它们与 C# 中的 String.Format 函数类似 // ================================================ -// More on functions +// 函数漫谈 // ================================================ -// F# is a true functional language -- functions are first -// class entities and can be combined easily to make powerful -// constructs +// F# 是函数式编程语言:函数是其一等公民,通过组合不同函数可以实现强大的功能 // Modules are used to group functions together // Indentation is needed for each nested module. From ff2da1628c19b66a69674a998e4e2c1f6c3833a4 Mon Sep 17 00:00:00 2001 From: Endericedragon Fu Date: Wed, 27 Aug 2025 11:32:59 +0800 Subject: [PATCH 5/9] Completed translation before Array --- zh-cn/fsharp.md | 58 ++++++++++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/zh-cn/fsharp.md b/zh-cn/fsharp.md index 03fd5c40ee..a917e15b37 100644 --- a/zh-cn/fsharp.md +++ b/zh-cn/fsharp.md @@ -136,72 +136,72 @@ printfn "A string %s, and something generic %A" "hello" [1; 2; 3; 4] // F# 是函数式编程语言:函数是其一等公民,通过组合不同函数可以实现强大的功能 -// Modules are used to group functions together -// Indentation is needed for each nested module. +// 模块(Modules)可以将一系列函数组织到一起 +// 每个模块使用标识符(Indentation)来唯一标记 module FunctionExamples = - // define a simple adding function + // 定义一个简单的求和函数 let add x y = x + y - // basic usage of a function + // 函数的基础使用 let a = add 1 2 printfn "1 + 2 = %i" a - // partial application to "bake in" parameters + // 函数的“部分应用”(partial application)可事先“固化”参数 let add42 = add 42 let b = add42 1 printfn "42 + 1 = %i" b - // composition to combine functions + // 函数的组合(composition)可将多个函数“串接”起来 let add1 = add 1 let add2 = add 2 let add3 = add1 >> add2 let c = add3 7 printfn "3 + 7 = %i" c - // higher order functions + // 高阶函数 [1..10] |> List.map add3 |> printfn "new list is %A" - // lists of functions, and more + // 函数列表,以及 List.reduce 函数 let add6 = [add1; add2; add3] |> List.reduce (>>) let d = add6 7 printfn "1 + 2 + 3 + 7 = %i" d // ================================================ -// Lists and collection +// 列表与集合(collection) // ================================================ -// There are three types of ordered collection: -// * Lists are most basic immutable collection. -// * Arrays are mutable and more efficient when needed. -// * Sequences are lazy and infinite (e.g. an enumerator). +// F# 内置了三种有序集合: +// * 列表(List)是最基本的、不可变的集合类型 +// * 数组(Arrays)是可变的,按需使用可令程序更高效 +// * 序列(Sequences)是惰性的、无限的集合类型(例如枚举器enumerator) // -// Other collections include immutable maps and sets -// plus all the standard .NET collections +// 除此以外,还有诸如不可变哈希表、不可变哈希集合、 +// 以及所有 .NET 中定义的标准集合类型等 module ListExamples = - // lists use square brackets + // 列表使用方括号 let list1 = ["a"; "b"] - let list2 = "c" :: list1 // :: is prepending - let list3 = list1 @ list2 // @ is concat + let list2 = "c" :: list1 // :: 将元素添加到开头 + let list3 = list1 @ list2 // @ 将两个列表连接起来 - // list comprehensions (aka generators) + // 列表推导式(list comprehensions),也被称为生成器(generators) let squares = [for i in 1..10 do yield i * i] - // A prime number generator - // - this is using a short notation for the pattern matching syntax - // - (p::xs) is 'first :: tail' of the list, could also be written as p :: xs - // this means this matches 'p' (the first item in the list), and xs is the rest of the list - // this is called the 'cons pattern' - // - uses 'rec' keyword, which is necessary when using recursion + // 素数生成器 + // - 本例采用了模式匹配的简写语法 + // - (p::xs) 匹配列表的 “第一个元素 :: 其余所有元素” ,写成 p :: xs也可以 + // 此时,p匹配到列表的第一个元素,而其余元素被xs匹配到 + // 这种写法被称为构造模式(cons pattern) + // - 在写递归函数时,必须使用 "rec" 关键字 let rec sieve = function | (p::xs) -> p :: sieve [ for x in xs do if x % p > 0 then yield x ] | [] -> [] let primes = sieve [2..50] printfn "%A" primes - // pattern matching for lists + // 对列表进行模式匹配 let listMatcher aList = match aList with | [] -> printfn "the list is empty" @@ -214,7 +214,7 @@ module ListExamples = listMatcher [1] listMatcher [] - // recursion using lists + // 接受列表作参数的递归函数 let rec sum aList = match aList with | [] -> 0 @@ -222,7 +222,7 @@ module ListExamples = sum [1..10] // ----------------------------------------- - // Standard library functions + // 列表的标准库函数 // ----------------------------------------- // map @@ -233,7 +233,7 @@ module ListExamples = let even x = x % 2 = 0 [1..10] |> List.filter even - // many more -- see documentation + // 还有很多,详见文档 module ArrayExamples = From 960debb503b0d21496eef997fbf9303bf8eebb61 Mon Sep 17 00:00:00 2001 From: Endericedragon Fu Date: Thu, 28 Aug 2025 17:52:49 +0800 Subject: [PATCH 6/9] Completed translation before .Net Compatibility --- zh-cn/fsharp.md | 208 +++++++++++++++++++++++------------------------- 1 file changed, 100 insertions(+), 108 deletions(-) diff --git a/zh-cn/fsharp.md b/zh-cn/fsharp.md index a917e15b37..342c56331b 100644 --- a/zh-cn/fsharp.md +++ b/zh-cn/fsharp.md @@ -237,11 +237,11 @@ module ListExamples = module ArrayExamples = - // arrays use square brackets with bar + // 数组(Array)用 [| 和 |] 包裹 let array1 = [| "a"; "b" |] - let first = array1.[0] // indexed access using dot + let first = array1.[0] // 用 . 来索引元素 - // pattern matching for arrays is same as for lists + // 数组和列表的模式匹配语法完全相同 let arrayMatcher aList = match aList with | [| |] -> printfn "the array is empty" @@ -251,7 +251,7 @@ module ArrayExamples = arrayMatcher [| 1; 2; 3; 4 |] - // Standard library functions just as for List + // Array的标准库函数和List也几乎一样 [| 1..10 |] |> Array.map (fun i -> i + 3) @@ -261,78 +261,78 @@ module ArrayExamples = module SequenceExamples = - // sequences use curly braces + // 序列(Sequence)用大括号包裹 let seq1 = seq { yield "a"; yield "b" } - // sequences can use yield and - // can contain subsequences + // 序列可以使用 "yield" 关键字,也可以包含子序列 let strange = seq { - // "yield" adds one element + // "yield" 向序列中增添1个元素 yield 1; yield 2; - // "yield!" adds a whole subsequence + // "yield!" 则是增添一个子序列 yield! [5..10] yield! seq { for i in 1..10 do if i % 2 = 0 then yield i }} - // test + // 试试看吧! strange |> Seq.toList - // Sequences can be created using "unfold" - // Here's the fibonacci series + // 序列可以通过 "Seq.unfold" 函数来创建 + // 下例演示如何用这个函数创建斐波那契数列 let fib = Seq.unfold (fun (fst,snd) -> Some(fst + snd, (snd, fst + snd))) (0,1) - // test + // 试试看吧! let fib10 = fib |> Seq.take 10 |> Seq.toList printf "first 10 fibs are %A" fib10 // ================================================ -// Data Types +// 数据类型 // ================================================ module DataTypeExamples = - // All data is immutable by default + // 默认情况下,所有的数据类型均是不可变的 - // Tuples are quick 'n easy anonymous types - // -- Use a comma to create a tuple + // 元组(Tuple)是一种简单快捷的匿名类型 + // -- 使用逗号即可创建元组 let twoTuple = 1, 2 let threeTuple = "a", 2, true - // Pattern match to unpack - let x, y = twoTuple // sets x = 1, y = 2 + // 同样,使用模式匹配来解包元组 + let x, y = twoTuple // x, y分别被赋值为1, 2 // ------------------------------------ - // Record types have named fields + // 记录(Record)类型由命名域构成(译者注:类似class的成员变量) + // 译者注:由于“记录”一词听起来像动词,下文将以英文原文Record来指代 // ------------------------------------ - // Use "type" with curly braces to define a record type + // 使用 "type" 关键字和大括号来定义Record类型 type Person = {First:string; Last:string} - // Use "let" with curly braces to create a record + // 使用 "let" 关键字和大括号来创建Record实例 let person1 = {First="John"; Last="Doe"} - // Pattern match to unpack - let {First = first} = person1 // sets first="John" + // 同样,使用模式匹配来解包Record实例 + let {First = first} = person1 // first被赋值为"John" // ------------------------------------ - // Union types (aka variants) have a set of choices - // Only one case can be valid at a time. + // 联合类型(Union或Variants,类似于Rust中的枚举类型)拥有一系列的取值选项。其实例仅能从中取其一。 + // 译者注:由于联合类型与Rust中的枚举类型(enum)很相似,故后文将以“枚举类型”指代之 // ------------------------------------ - // Use "type" with bar/pipe to define a union type + // 使用 "type" 关键字和竖线/管道符来定义枚举类型 type Temp = | DegreesC of float | DegreesF of float - // Use one of the cases to create one + // 使用一个选项来创建枚举实例 let temp1 = DegreesF 98.6 let temp2 = DegreesC 37.0 - // Pattern match on all cases to unpack + // 模式匹配可以解包枚举实例 let printTemp = function | DegreesC t -> printfn "%f degC" t | DegreesF t -> printfn "%f degF" t @@ -341,36 +341,33 @@ module DataTypeExamples = printTemp temp2 // ------------------------------------ - // Recursive types + // 递归类型 // ------------------------------------ - // Types can be combined recursively in complex ways - // without having to create subclasses + // 类型可以通过递归组合成复杂的类型,无需创建子类 type Employee = | Worker of Person - | Manager of Employee list + | Manager of Employee list // 译者注:这儿发生了递归定义 let jdoe = {First="John"; Last="Doe"} let worker = Worker jdoe // ------------------------------------ - // Modeling with types + // 使用枚举类型建模 // ------------------------------------ - // Union types are great for modeling state without using flags + // 枚举类型非常适合用于表述某种状态,再也不需要用数字等标志位(flag)来表征状态啦! type EmailAddress = - | ValidEmailAddress of string - | InvalidEmailAddress of string + | ValidEmailAddress of string // 状态:合法邮件地址 + | InvalidEmailAddress of string // 状态:不合法邮件地址 let trySendEmail email = - match email with // use pattern matching - | ValidEmailAddress address -> () // send - | InvalidEmailAddress address -> () // don't send + match email with // 使用模式匹配 + | ValidEmailAddress address -> () // 可以发送 + | InvalidEmailAddress address -> () // 不能发送 - // The combination of union types and record types together - // provide a great foundation for domain driven design. - // You can create hundreds of little types that accurately - // reflect the domain. + // 组合使用枚举类型和Record类型为“域驱动的软件设计”(Domain Driven Design)提供了良好基础。 + // 您可以定义数以百计的类型,每一种都精准地反映着一个域(Domain) type CartItem = { ProductCode: string; Qty: int } type Payment = Payment of float @@ -378,26 +375,25 @@ module DataTypeExamples = type PaidCartData = { PaidItems: CartItem list; Payment: Payment} type ShoppingCart = - | EmptyCart // no data + | EmptyCart // 空购物车,没有数据 | ActiveCart of ActiveCartData | PaidCart of PaidCartData // ------------------------------------ - // Built in behavior for types + // 数据类型的内置行为 // ------------------------------------ - // Core types have useful "out-of-the-box" behavior, no coding needed. - // * Immutability - // * Pretty printing when debugging - // * Equality and comparison - // * Serialization + // 核心数据类型提供了开箱即用的默认行为与性质,无需额外编码。 + // * 不可变性 + // * 漂亮的打印输出,在debug时尤其好用 + // * 相等性与可比性 + // * 可序列化性 - // Pretty printing using %A + // 使用 %A 来输出复杂数据类型 printfn "twoTuple=%A,\nPerson=%A,\nTemp=%A,\nEmployee=%A" twoTuple person1 temp1 worker - // Equality and comparison built in. - // Here's an example with cards. + // 下列扑克牌示例展示了 F# 中内置的相等性与可比较性 type Suit = Club | Diamond | Spade | Heart type Rank = Two | Three | Four | Five | Six | Seven | Eight | Nine | Ten | Jack | Queen | King | Ace @@ -405,34 +401,33 @@ module DataTypeExamples = let hand = [ Club, Ace; Heart, Three; Heart, Ace; Spade, Jack; Diamond, Two; Diamond, Ace ] - // sorting + // 排序 List.sort hand |> printfn "sorted hand is (low to high) %A" List.max hand |> printfn "high card is %A" List.min hand |> printfn "low card is %A" // ================================================ -// Active patterns +// 主动模式(Active patterns) // ================================================ module ActivePatternExamples = - // F# has a special type of pattern matching called "active patterns" - // where the pattern can be parsed or detected dynamically. + // F# 中,有一种被称为“主动模式”的特殊模式匹配 + // 它可以在模式匹配中动态解析或检测模式(pattern)。 - // "banana clips" are the syntax for active patterns + // 主动匹配的语法形似 "banana clips" (译者注:确实不知道banana clips是啥意思) - // You can use "elif" instead of "else if" in conditional expressions. - // They are equivalent in F# + // 您可以用elif代替else if,它们在 F# 中完全等价 - // for example, define an "active" pattern to match character types... + // 下列示例使用主动模式去匹配不同类型的字符... let (|Digit|Letter|Whitespace|Other|) ch = if System.Char.IsDigit(ch) then Digit elif System.Char.IsLetter(ch) then Letter elif System.Char.IsWhiteSpace(ch) then Whitespace else Other - // ... and then use it to make parsing logic much clearer + // ...然后使用它,可以看到解析逻辑十分清晰 let printChar ch = match ch with | Digit -> printfn "%c is a Digit" ch @@ -440,19 +435,19 @@ module ActivePatternExamples = | Whitespace -> printfn "%c is a Whitespace" ch | _ -> printfn "%c is something else" ch - // print a list + // 用主动模式处理并打印一个列表 ['a'; 'b'; '1'; ' '; '-'; 'c'] |> List.iter printChar // ----------------------------------- - // FizzBuzz using active patterns + // 用主动模式实现FizzBuzz // ----------------------------------- - // You can create partial matching patterns as well - // Just use underscore in the definition, and return Some if matched. + // 您也可以在主动模式中实现“部分匹配” + // 只需在定义中使用下划线,并在匹配成功时返回 Some 即可 let (|MultOf3|_|) i = if i % 3 = 0 then Some MultOf3 else None let (|MultOf5|_|) i = if i % 5 = 0 then Some MultOf5 else None - // the main function + // fizzbuzz的主函数 let fizzBuzz i = match i with | MultOf3 & MultOf5 -> printf "FizzBuzz, " @@ -460,95 +455,92 @@ module ActivePatternExamples = | MultOf5 -> printf "Buzz, " | _ -> printf "%i, " i - // test + // 试试看吧! [1..20] |> List.iter fizzBuzz // ================================================ -// Conciseness +// 简明的 F# // ================================================ module AlgorithmExamples = - // F# has a high signal/noise ratio, so code reads - // almost like the actual algorithm + // F# 代码的“信噪比”很高,阅读代码时很容易就能弄明白算法的意图 - // ------ Example: define sumOfSquares function ------ + // ------ 例子: 计算平方和 ------ let sumOfSquares n = - [1..n] // 1) take all the numbers from 1 to n - |> List.map square // 2) square each one - |> List.sum // 3) sum the results + [1..n] // 1) 取从 1 到 n 的所有整数 + |> List.map square // 2) 给每个整数求平方 + |> List.sum // 3) 将上一步的结果求和 - // test + // 试试看吧! sumOfSquares 100 |> printfn "Sum of squares = %A" - // ------ Example: define a sort function ------ + // ------ 例子: 排序 ------ + // 译者注:下列示例实现的是朴素的快速排序算法 let rec sort list = match list with - // If the list is empty + // 若 list 是空表... | [] -> - [] // return an empty list - // If the list is not empty - | firstElem::otherElements -> // take the first element - let smallerElements = // extract the smaller elements - otherElements // from the remaining ones + [] // ...则返回空表 + // 否则... + | firstElem::otherElements -> // 取其第一个元素 + let smallerElements = // 从剩余元素中提取比它小的 + otherElements |> List.filter (fun e -> e < firstElem) - |> sort // and sort them - let largerElements = // extract the larger ones - otherElements // from the remaining ones + |> sort // 并排序 + let largerElements = // 同理,从剩余元素中提取比它大的 + otherElements |> List.filter (fun e -> e >= firstElem) - |> sort // and sort them - // Combine the 3 parts into a new list and return it + |> sort // 并排序 + // 最后,将这三部分组合起来,返回一个新的列表 List.concat [smallerElements; [firstElem]; largerElements] - // test + // 试试看吧! sort [1; 5; 23; 18; 9; 1; 3] |> printfn "Sorted = %A" // ================================================ -// Asynchronous Code +// 异步编程 // ================================================ module AsyncExample = - // F# has built-in features to help with async code - // without encountering the "pyramid of doom" - // - // The following example downloads a set of web pages in parallel. + // F# 内置了对异步编程的支持 + // 从而规避了缩进地狱问题("pyramid of doom") + // 下列示例展示了如何使用异步编程,实现同时下载多个网页 open System.Net open System open System.IO open Microsoft.FSharp.Control.CommonExtensions - // Fetch the contents of a URL asynchronously + // 异步地访问URL,并获取其内容 let fetchUrlAsync url = - async { // "async" keyword and curly braces - // creates an "async" object + async { // "async" 关键词和大括号将创建一个异步对象 ("async" object) let req = WebRequest.Create(Uri(url)) use! resp = req.AsyncGetResponse() - // use! is async assignment + // use! 的意思是异步赋值,类似于JavaScript的await use stream = resp.GetResponseStream() - // "use" triggers automatic close() - // on resource at end of scope + // "use" 会让资源在当前作用域结束时自动 close() use reader = new IO.StreamReader(stream) let html = reader.ReadToEnd() printfn "finished downloading %s" url - } + } - // a list of sites to fetch + // 准备以下网页喂给爬虫 let sites = ["http://www.bing.com"; "http://www.google.com"; "http://www.microsoft.com"; "http://www.amazon.com"; "http://www.yahoo.com"] - // do it + // 来试试看吧! sites - |> List.map fetchUrlAsync // make a list of async tasks - |> Async.Parallel // set up the tasks to run in parallel - |> Async.RunSynchronously // start them off + |> List.map fetchUrlAsync // 把每个URL都包装成一个异步任务 + |> Async.Parallel // 令所有任务并发地运行 + |> Async.RunSynchronously // 开始运行 // ================================================ -// .NET compatibility +// .NET 兼容性 // ================================================ module NetCompatibilityExamples = From d061964136ca34d488e96b5dab3405c64566373d Mon Sep 17 00:00:00 2001 From: Endericedragon Fu Date: Fri, 29 Aug 2025 11:03:30 +0800 Subject: [PATCH 7/9] Completed all translation work, ready for PR --- zh-cn/fsharp.md | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/zh-cn/fsharp.md b/zh-cn/fsharp.md index 342c56331b..db8bedec75 100644 --- a/zh-cn/fsharp.md +++ b/zh-cn/fsharp.md @@ -545,17 +545,17 @@ module AsyncExample = module NetCompatibilityExamples = - // F# can do almost everything C# can do, and it integrates - // seamlessly with .NET or Mono libraries. + // C#能干的活,F# 基本上都能做。同时,F# 还无缝集成了 .Net 或 Mono 的库 + // 译者注:Mono库(Mono Libraries)的含义不太确定 - // ------- work with existing library functions ------- + // ------- 使用已有的库函数 ------- let (i1success, i1) = System.Int32.TryParse("123"); if i1success then printfn "parsed as %i" i1 else printfn "parse failed" - // ------- Implement interfaces on the fly! ------- + // ------- 简简单单实现接口(interface) ------- - // create a new object that implements IDisposable + // 创建一个实现了 IDisposable 的对象 let makeResource name = { new System.IDisposable with member this.Dispose() = printfn "%s disposed" name } @@ -571,48 +571,47 @@ module NetCompatibilityExamples = printfn "using second resource" printfn "done." - // ------- Object oriented code ------- + // ------- 面向对象编程 ------- - // F# is also a fully fledged OO language. - // It supports classes, inheritance, virtual methods, etc. + // F# 对面向对象编程的支持也很成熟,支持类、接口、虚函数等 - // interface with generic type + // 带有泛型的接口 type IEnumerator<'a> = abstract member Current : 'a abstract MoveNext : unit -> bool - // abstract base class with virtual methods + // 带有虚函数的抽象基类 [] type Shape() = - // readonly properties + // 只读的成员变量 abstract member Width : int with get abstract member Height : int with get - // non-virtual method + // 非虚函数 member this.BoundingArea = this.Height * this.Width - // virtual method with base implementation + // 虚函数,且带有默认实现 abstract member Print : unit -> unit default this.Print () = printfn "I'm a shape" - // concrete class that inherits from base class and overrides + // 具象子类,继承上述抽象基类,并覆写(override)了其中的函数 type Rectangle(x:int, y:int) = inherit Shape() override this.Width = x override this.Height = y override this.Print () = printfn "I'm a Rectangle" - // test + // 试试看吧! let r = Rectangle(2, 3) printfn "The width is %i" r.Width printfn "The area is %i" r.BoundingArea r.Print() - // ------- extension methods ------- + // ------- 扩展已有类的方法 ------- - // Just as in C#, F# can extend existing classes with extension methods. + // 与 C# 一样,F# 也可以使用扩展语法来扩展已有类的方法 type System.String with member this.StartsWithA = this.StartsWith "A" - // test + // 试试看吧! let s = "Alice" printfn "'%s' starts with an 'A' = %A" s s.StartsWithA From 84484a8ed5121debb8c992f5afdd8779266cb526 Mon Sep 17 00:00:00 2001 From: Endericedragon Fu Date: Sun, 31 Aug 2025 08:37:33 +0800 Subject: [PATCH 8/9] =?UTF-8?q?Fix=20a=20typo=20(=E7=BC=96=E8=AF=91?= =?UTF-8?q?=E5=99=A8=20->=20=E7=BC=96=E8=AF=91=E6=9C=9F)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- zh-cn/fsharp.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zh-cn/fsharp.md b/zh-cn/fsharp.md index db8bedec75..c1ba3417df 100644 --- a/zh-cn/fsharp.md +++ b/zh-cn/fsharp.md @@ -9,7 +9,7 @@ filename: learnfsharp.fs F# 是一款通用的、函数式的面向对象语言。它既开源又免费,并且在Linux、Mac和Windows等多平台上均可运行。 -这款语言拥有强大的类型系统,许多错误在编译器即可被发现并随之被修复。不过,由于 F# 采用了类型推理技术(译者注:不需手动指定,而是通过上下文自动推断变量的类型),在读代码时往往给人一种动态类型语言的错觉。 +这款语言拥有强大的类型系统,许多错误在编译期间即可被发现并随之被修复。不过,由于 F# 采用了类型推理技术(译者注:不需手动指定,而是通过上下文自动推断变量的类型),在读代码时往往给人一种动态类型语言的错觉。 需要留意的是, F# 的语法和“类C语言”有较大不同: - 使用**缩进**来组织代码块(类似Python那样),而不是大括号。 From a7079202f1d070095fa230be4ddf30d35b5ecb06 Mon Sep 17 00:00:00 2001 From: Endericedragon Fu Date: Mon, 1 Sep 2025 15:02:25 +0800 Subject: [PATCH 9/9] =?UTF-8?q?Corrected=20some=20terms.=20Now=20all=20lis?= =?UTF-8?q?ts=20are=20called=20"=E5=88=97=E8=A1=A8"=20and=20all=20arrays?= =?UTF-8?q?=20are=20called=20"=E6=95=B0=E7=BB=84".=20Besides,=20add=20extr?= =?UTF-8?q?a=20contents=20to=20explain=20"active=20pattern".?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- zh-cn/fsharp.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zh-cn/fsharp.md b/zh-cn/fsharp.md index c1ba3417df..e6ea5ab1d0 100644 --- a/zh-cn/fsharp.md +++ b/zh-cn/fsharp.md @@ -45,7 +45,7 @@ printfn "%d" xRef.Value // 10 xRef.Value <- 11 printfn "%d" xRef.Value // 11 -let a = [ref 0; ref 1] // 装有可变元素的数组 +let a = [ref 0; ref 1] // 装有可变元素的列表 a[0].Value <- 2 // ------ 列表Lists ------ @@ -415,6 +415,7 @@ module ActivePatternExamples = // F# 中,有一种被称为“主动模式”的特殊模式匹配 // 它可以在模式匹配中动态解析或检测模式(pattern)。 + // 译者注:译者个人倾向于把此所谓“主动模式”理解为,自定义某个数据类型在接受模式匹配时,会返回哪些情况 // 主动匹配的语法形似 "banana clips" (译者注:确实不知道banana clips是啥意思)