Note
ãã®ããŒãžã«ã¢ã¯ã»ã¹ããã«ã¯ãæ¿èªãå¿ èŠã§ãã ãµã€ã³ã€ã³ãŸãã¯ãã£ã¬ã¯ããªã®å€æŽã詊ãããšãã§ããŸãã
ãã®ããŒãžã«ã¢ã¯ã»ã¹ããã«ã¯ãæ¿èªãå¿ èŠã§ãã ãã£ã¬ã¯ããªã®å€æŽã詊ãããšãã§ããŸãã
次ã®èŠåã¯ã倧ã㪠F# ã³ãŒãããŒã¹ã®äœ¿çšçµéšããäœæããããã®ã§ãã ãåªãã F# ã³ãŒãã® 5 ã€ã®ååãã¯ãåæšå¥šäºé ã®åºç€ãšãªããŸãã ãããã¯ãF# ã³ã³ããŒãã³ã ãã¶ã€ã³ã®ã¬ã€ãã©ã€ã³ãã«é¢é£ããŠããŸãããã©ã€ãã©ãªãªã©ã®ã³ã³ããŒãã³ãã ãã§ãªãããã¹ãŠã® F# ã³ãŒãã«é©çšãããŸãã
ã³ãŒãã®æŽç
F# ã«ã¯ãã³ãŒããæŽçããããã®äž»ãªæ¹æ³ãšããŠãã¢ãžã¥ãŒã«ãšåå空éã® 2 ã€ããããŸãã ãããã¯äŒŒãŠããŸãããæ¬¡ã®ç¹ãç°ãªããŸãã
- åå空éã¯ã.NET åå空éãšããŠã³ã³ãã€ã«ãããŸãã ã¢ãžã¥ãŒã«ã¯ãéçã¯ã©ã¹ãšããŠã³ã³ãã€ã«ãããŸãã
- åå空éã¯åžžã«æäžäœã¬ãã«ã§ãã ã¢ãžã¥ãŒã«ã¯ãæäžäœã¬ãã«ã«ããããšããä»ã®ã¢ãžã¥ãŒã«å ã§å ¥ãåã«ããããšãã§ããŸãã
- åå空éã¯ãè€æ°ã®ãã¡ã€ã«ã«ãŸãããããšãã§ããŸãã ã¢ãžã¥ãŒã«ã§ã¯ã§ããŸããã
- ã¢ãžã¥ãŒã«ã¯ã
[<RequireQualifiedAccess>]ããã³[<AutoOpen>]ã§ä¿®é£Ÿã§ããŸãã
次ã®ã¬ã€ãã©ã€ã³ã¯ããããã䜿çšããŠã³ãŒããæŽçããéã«åœ¹ç«ã¡ãŸãã
æäžäœã¬ãã«ã§ã¯åå空éãåªå ãã
ãããªãã¯ã«äœ¿çšã§ããã³ãŒãã§ã¯ãæäžäœã¬ãã«ã®ã¢ãžã¥ãŒã«ããåå空éãåªå
ãããŸãã ããã㯠.NET åå空éãšããŠã³ã³ãã€ã«ããããããC# ã§ã¯ using static ãæå®ããããšãªã䜿çšã§ããŸãã
// Recommended.
namespace MyCode
type MyClass() =
...
æäžäœã¬ãã«ã®ã¢ãžã¥ãŒã«ã䜿çšãããšãF# ããã®ã¿åŒã³åºãå Žåã¯éãããªããããããŸããããC# ã®ã³ã³ã·ã¥ãŒããŒã«ãšã£ãŠã¯ãç¹å®ã® MyClass C# ã³ã³ã¹ãã©ã¯ããèªèããŠããªãå Žåã« MyCode ã using static ã¢ãžã¥ãŒã«ã§ä¿®é£Ÿããå¿
èŠããããããåŒã³åºãå
ãäºæããŠããªãå¯èœæ§ããããŸãã
// Will be seen as a static class outside F#
module MyCode
type MyClass() =
...
[<AutoOpen>] ãæ
éã«é©çšãã
[<AutoOpen>] æ§æäœã¯ãåŒã³åºãå
ãå©çšå¯èœãªèŠçŽ ã®ã¹ã³ãŒãã䟵ãå¯èœæ§ããããŸãããŸãããã®ç±æ¥ãäœã§ãããã¯ãéæ³ãã®ããã«èª¬æã§ããŸããã ããã¯è¯ãããšã§ã¯ãããŸããã ãã®ã«ãŒã«ã®äŸå€ãšããŠãF# ã³ã¢ ã©ã€ãã©ãªèªäœããããŸã (ãã ããããã«ãå°ãè°è«ã®äœå°ããããŸã)ã
ãã ãããããªã㯠API ã®ãã«ããŒæ©èœãããããã®ãããªã㯠API ãšã¯å¥ã«æŽçããå¿ èŠãããå Žåã«äŸ¿å©ã§ãã
module MyAPI =
[<AutoOpen>]
module private Helpers =
let helper1 x y z =
...
let myFunction1 x =
let y = ...
let z = ...
helper1 x y z
ããã«ãããåŒã³åºãã®ãã³ã«ãã«ããŒãå®å šã«ä¿®é£Ÿããããšãªãã颿°ã®ãããªã㯠API ããå®è£ ã®è©³çްãæç¢ºã«åé¢ã§ããŸãã
ããã«ãæ¡åŒµã¡ãœãããšåŒãã«ããŒã®åå空éã¬ãã«ã§ã®å
¬éãã[<AutoOpen>] ã䜿çšããŠç°¡æœã«è¡šçŸã§ããŸãã
ååãç«¶åããå¯èœæ§ãããå Žåããèªã¿ããããåäžãããå Žåã«ã¯å¿
ã [<RequireQualifiedAccess>] ã䜿çšãã
ã¢ãžã¥ãŒã«ã« [<RequireQualifiedAccess>] 屿§ã远å ãããšãã¢ãžã¥ãŒã«ãéãããšãã§ããªãããšãããã³ã¢ãžã¥ãŒã«ã®èŠçŽ ãžã®åç
§ã«ã¯æç€ºçãªä¿®é£Ÿã¢ã¯ã»ã¹ãå¿
èŠã§ããããšã瀺ãããŸãã ããšãã°ãMicrosoft.FSharp.Collections.List ã¢ãžã¥ãŒã«ã«ã¯ãã®å±æ§ããããŸãã
ããã¯ãã¢ãžã¥ãŒã«ã®é¢æ°ãšå€ã®ååããä»ã®ã¢ãžã¥ãŒã«ã®ååãšç«¶åããå¯èœæ§ãããå Žåã«äŸ¿å©ã§ãã 修食ãããã¢ã¯ã»ã¹ãèŠæ±ãããšãã©ã€ãã©ãªã®é·æçãªä¿å®æ§ãšçºå±æ§ãå€§å¹ ã«åäžãããããšãã§ããŸãã
[<RequireQualifiedAccess>]
module StringTokenization =
let parse s = ...
...
let s = getAString()
let parsed = StringTokenization.parse s // Must qualify to use 'parse'
open ã¹ããŒãã¡ã³ããäœçžçã«äžŠã¹æ¿ãã
F# ã§ã¯ã宣èšã®é åºã¯ãopen ã¹ããŒãã¡ã³ãïŒããã³åŸã«openãšããŠã ãèšåãããopen typeïŒãå«ããéèŠã§ãã ããã¯ãusing ãš using static ã®å¹æããã¡ã€ã«å
ã®ã¹ããŒãã¡ã³ãã®é åºã«äŸåããªã C# ãšã¯ç°ãªããŸãã
F# ã§ã¯ãã¹ã³ãŒãå
ã§éãããèŠçŽ ã¯ãæ¢ã«ååšããä»ã®èŠçŽ ãã·ã£ããŠã§ããŸãã ããã¯ãopen ã¹ããŒãã¡ã³ããäžŠã¹æ¿ãããšã³ãŒãã®æå³ãå€ããå¯èœæ§ããããšããããšã§ãã ãã®çµæããã¹ãŠã® open ã¹ããŒãã¡ã³ãã®ä»»æã®äžŠã¹æ¿ã (ããšãã°ãè±æ°åé ) ã䜿çšããããšã¯æšå¥šãããŸããããããªããšãäºæ³ãšã¯ç°ãªãåäœãçæãããŸãã
代ããã«ãäœçžçã«äžŠã¹æ¿ããããšããå§ãããŸããã€ãŸããopen ã¹ããŒãã¡ã³ãããã·ã¹ãã ã® "ã¬ã€ã€ãŒ" ãå®çŸ©ãããŠããé åºã§äžŠã¹æ¿ããŸãã ç°ãªãããããž ã¬ã€ã€ãŒå
ã§è±æ°åé ã®äžŠã¹æ¿ããè¡ãããšãã§ããŸãã
äŸãšããŠãF# ã³ã³ãã€ã© ãµãŒãã¹ã®ãããªã㯠API ãã¡ã€ã«ãäœçžçã«äžŠã¹æ¿ãããã®ã次ã«ç€ºããŸãã
namespace Microsoft.FSharp.Compiler.SourceCodeServices
open System
open System.Collections.Generic
open System.Collections.Concurrent
open System.Diagnostics
open System.IO
open System.Reflection
open System.Text
open FSharp.Compiler
open FSharp.Compiler.AbstractIL
open FSharp.Compiler.AbstractIL.Diagnostics
open FSharp.Compiler.AbstractIL.IL
open FSharp.Compiler.AbstractIL.ILBinaryReader
open FSharp.Compiler.AbstractIL.Internal
open FSharp.Compiler.AbstractIL.Internal.Library
open FSharp.Compiler.AccessibilityLogic
open FSharp.Compiler.Ast
open FSharp.Compiler.CompileOps
open FSharp.Compiler.CompileOptions
open FSharp.Compiler.Driver
open Internal.Utilities
open Internal.Utilities.Collections
æ¹è¡ã§ããããž ã¬ã€ã€ãŒãåé¢ããããã®åŸã§åã¬ã€ã€ãŒãè±æ°åé ã«äžŠã¹æ¿ããããŸãã ããã«ããã誀ã£ãŠå€ãã·ã£ããŠããããšãªãã³ãŒããæŽçã§ããŸãã
ã¯ã©ã¹ã䜿çšããŠå¯äœçšã®ããå€ãå°ã蟌ãã
ããŒã¿ããŒã¹ãŸãã¯ãã®ä»ã®ãªã¢ãŒã ãªãœãŒã¹ãžã®ã³ã³ããã¹ãã®ã€ã³ã¹ã¿ã³ã¹åãªã©ãå€ã®åæåã«ãã£ãŠå¯äœçšãçããå Žåãå€ããããŸãã æ¬¡ã®ããã«ãããããã¢ãžã¥ãŒã«å ã§åæåããŠåŸç¶ã®é¢æ°ã§äœ¿çšããããšã¯é åçã§ãã
// Not recommended, side-effect at static initialization
module MyApi =
let dep1 = File.ReadAllText "/Users/<name>/config-options.txt"
let dep2 = Environment.GetEnvironmentVariable "DEP_2"
let private r = Random()
let dep3() = r.Next() // Problematic if multiple threads use this
let function1 arg = doStuffWith dep1 dep2 dep3 arg
let function2 arg = doStuffWith dep1 dep2 dep3 arg
å€ãã®å Žåãããã¯æ¬¡ã®ãããªçç±ã§åé¡ã«ãªããŸãã
æåã«ãã¢ããªã±ãŒã·ã§ã³æ§æã¯ dep1 ãš dep2 ã䜿çšããŠã³ãŒãããŒã¹ã«ããã·ã¥ãããŸãã ãã倧ããªã³ãŒãããŒã¹ã§ã¯ããããç¶æããã®ã¯å°é£ã§ãã
2 çªç®ã«ãã³ã³ããŒãã³ãèªäœã§è€æ°ã®ã¹ã¬ããã䜿çšããå Žåãéçã«åæåãããããŒã¿ã«ã¯ãã¹ã¬ãã ã»ãŒãã§ã¯ãªãå€ãå«ããªãã§ãã ããã ããã¯ãdep3 ãæç¢ºã«éåããŠããŸãã
æåŸã«ãã¢ãžã¥ãŒã«ã®åæåã¯ãã³ã³ãã€ã«åäœå
šäœã®éçã³ã³ã¹ãã©ã¯ã¿ãŒã«ã³ã³ãã€ã«ãããŸãã ãã®ã¢ãžã¥ãŒã«ã® let ã§ãã€ã³ããããå€ã®åæåã§ãšã©ãŒãçºçããå Žåããã®ãšã©ãŒã¯ TypeInitializationException ãšããŠãããã§ã¹ããæã¡ãã¢ããªã±ãŒã·ã§ã³ã®æå¹æéå
šäœã«ããã£ãŠãã£ãã·ã¥ãããŸãã ããã«ãã£ãŠèšºæãå°é£ã«ãªãå ŽåããããŸãã éåžžã¯å€æã§ããå
éšäŸå€ããããŸããããããååšããªãå Žåãæ ¹æ¬åå ã«ã€ããŠã¯äœãéç¥ãããŸããã
代ããã«ãåçŽãªã¯ã©ã¹ã䜿çšããŠäŸåé¢ä¿ãä¿æããã ãã«ããŸãã
type MyParametricApi(dep1, dep2, dep3) =
member _.Function1 arg1 = doStuffWith dep1 dep2 dep3 arg1
member _.Function2 arg2 = doStuffWith dep1 dep2 dep3 arg2
ããã«ãããæ¬¡ã®ããšãå¯èœã«ãªããŸãã
- API èªäœã®å€éšã«äŸåç¶æ ãããã·ã¥ããŸãã
- API ã®å€éšã§æ§æãå®è¡ã§ããããã«ãªããŸãã
- äŸåããå€ã®åæåã§ãšã©ãŒãçºçããŠãã
TypeInitializationExceptionãšããŠçŸããå¯èœæ§ã¯äœãã§ãã - API ã®ãã¹ããç°¡åã«ãªããŸãã
ãšã©ãŒç®¡ç
å€§èŠæš¡ãªã·ã¹ãã ã«ããããšã©ãŒç®¡çã¯è€éã§åŸ®åŠãªäœæ¥ã§ãããã·ã¹ãã ããã©ãŒã«ã ãã¬ã©ã³ãã§é©åã«åäœããŠãããã©ããã確èªããããã®äžå šã®è§£æ±ºçã¯ãããŸããã æ¬¡ã®ã¬ã€ãã©ã€ã³ã§ã¯ããã®ãããªå°é£ãªäœæ¥ãè¡ãéã®ã¬ã€ãã³ã¹ãæäŸããŸãã
ããªãã®ãã¡ã€ã³ã«åºæã®åã§ããšã©ãŒã±ãŒã¹ãšäžæ£ãªç¶æ ã衚çŸãã
F# ã§ã¯ãå€å¥å ±çšäœã䜿çšããŠãåã·ã¹ãã å ã®åé¡ã®ããããã°ã©ã ã®ç¶æ ã衚ãããšãã§ããŸãã æ¬¡ã«äŸã瀺ããŸãã
type MoneyWithdrawalResult =
| Success of amount:decimal
| InsufficientFunds of balance:decimal
| CardExpired of DateTime
| UndisclosedFailure
ãã®å Žåãéè¡å£åº§ããã®åºéã«å€±æããå¯èœæ§ãããæ¢ç¥ã®æ¹æ³ã 3 ã€ãããŸãã åãšã©ãŒ ã±ãŒã¹ã¯åã§è¡šããããããããã°ã©ã å šäœã§å®å šã«åŠçã§ããŸãã
let handleWithdrawal amount =
let w = withdrawMoney amount
match w with
| Success am -> printfn $"Successfully withdrew %f{am}"
| InsufficientFunds balance -> printfn $"Failed: balance is %f{balance}"
| CardExpired expiredDate -> printfn $"Failed: card expired on {expiredDate}"
| UndisclosedFailure -> printfn "Failed: unknown"
äžè¬ã«ããã¡ã€ã³å ã§äœããã®ãšã©ãŒãçºçããå¯èœæ§ã®ããããŸããŸãªæ¹æ³ãã¢ãã«åã§ããå Žåããšã©ãŒåŠçã³ãŒãã¯ãéåžžã®ããã°ã©ã ãããŒã«å ããŠåŠçããå¿ èŠã®ãããã®ã§ã¯ãªããªããŸãã ããã¯åã«éåžžã®ããã°ã©ã ãããŒã®äžéšã§ãããäŸå€çãšã¯èŠãªãããŸããã ããã«ã¯ã以äžã® 2 ã€ã®äž»ãªå©ç¹ããããŸãã
- æéã®çµéãšå ±ã«ãã¡ã€ã³ãå€åããŠããä¿å®ã容æã«ãªããŸãã
- ãšã©ãŒã±ãŒã¹ã¯ãŠããããã¹ãããããããªããŸãã
ãšã©ãŒãåã§è¡šãããšãã§ããªãå Žåã«äŸå€ã䜿çšãã
åé¡ã®ãããã¡ã€ã³ã§è¡šçŸããããšãã§ããªããšã©ãŒããããŸãã ãã®çš®ã®ãšã©ãŒã¯æ¬è³ªçã« "äŸå€ç" ã§ãããããF# ã§ã¯äŸå€ãçºçãããŠãã£ããããããšãã§ããŸãã
ãŸãããäŸå€ã®ãã¶ã€ã³ã®ã¬ã€ãã©ã€ã³ããèªãããšããå§ãããŸãã ããã㯠F# ã«ãåœãŠã¯ãŸããŸãã
äŸå€ãçºçãããããã« F# ã§äœ¿çšã§ããäž»ãªæ§æèŠçŽ ã¯ã次ã®åªå é äœã§èæ ®ããå¿ èŠããããŸãã
| æ©èœ | æ§æ | ç®ç |
|---|---|---|
nullArg |
nullArg "argumentName" |
æå®ããåŒæ°åã䜿çšã㊠System.ArgumentNullException ãçºçãããŸãã |
invalidArg |
invalidArg "argumentName" "message" |
æå®ããåŒæ°åãšã¡ãã»ãŒãžã䜿çšã㊠System.ArgumentException ãçºçãããŸãã |
invalidOp |
invalidOp "message" |
æå®ããã¡ãã»ãŒãžã䜿çšã㊠System.InvalidOperationException ãçºçãããŸãã |
raise |
raise (ExceptionType("message")) |
äŸå€ãã¹ããŒããããã®æ±çšçãªã¡ã«ããºã ã |
failwith |
failwith "message" |
æå®ããã¡ãã»ãŒãžã䜿çšã㊠System.Exception ãçºçãããŸãã |
failwithf |
failwithf "format string" argForFormatString |
æžåŒæå®æååãšãã®å
¥åã«ãã£ãŠæ±ºå®ãããã¡ãã»ãŒãžã䜿çšã㊠System.Exception ãçºçãããŸãã |
å¿
èŠã«å¿ã㊠nullArgãinvalidArgãinvalidOp ãã¹ããŒããããã®ã¡ã«ããºã ãšããŠãArgumentNullExceptionãArgumentExceptionãInvalidOperationException ã䜿çšããŸãã
failwith 颿°ãš failwithf 颿°ã¯ãéåžžãç¹å®ã®äŸå€ã§ã¯ãªãåºæ¬ã® Exception åãçæãããããåé¿ããå¿
èŠããããŸãã ãäŸå€ã®ãã¶ã€ã³ã®ã¬ã€ãã©ã€ã³ãã«åŸã£ãŠãå¯èœãªéãããå
·äœçãªäŸå€ãçæããå¿
èŠããããŸãã
äŸå€åŠçæ§æã䜿çšãã
F# ã§ã¯ã次㮠try...with æ§æã䜿çšããŠäŸå€ãã¿ãŒã³ããµããŒãããŠããŸãã
try
tryGetFileContents()
with
| :? System.IO.FileNotFoundException as e -> // Do something with it here
| :? System.Security.SecurityException as e -> // Do something with it here
ãã¿ãŒã³ ãããã³ã°ã䜿çšããŠäŸå€ãçºçãããšãã«å®è¡ããæ©èœã調æŽããããšã¯ãã³ãŒããã¯ãªãŒã³ãªç¶æ ã«ä¿ã€å¿ èŠãããå Žåã«å°ãåä»ã«ãªãããšããããŸãã ãã®ãããªåŠçãè¡ãæ¹æ³ã® 1 ã€ã«ããšã©ãŒã®çºçããã±ãŒã¹ãäŸå€èªäœã§å²ãæ©èœãã°ã«ãŒãåããææ®µãšããŠãã¢ã¯ãã£ã ãã¿ãŒã³ã䜿çšããæ¹æ³ããããŸãã ããšãã°ãAPIãå©çšããŠããŠãäŸå€ãã¹ããŒãããéã«ãäŸå€ã¡ã¿ããŒã¿ã«äŸ¡å€ã®ããæ å ±ãå«ãŸããå ŽåããããŸãã ã¢ã¯ãã£ã ãã¿ãŒã³å ã§ãã£ããã£ãããäŸå€ã®æ¬äœå ã«ããæçšãªå€ãã©ããè§£é€ãããã®å€ãè¿ãããšã¯ç¶æ³ã«ãã£ãŠã¯åœ¹ã«ç«ã¡ãŸãã
ã¢ããã«ãããšã©ãŒåŠçã䜿çšããŠäŸå€ã眮ãæããªãããã«ããŠãã ãã
çŽç²é¢æ°åãã©ãã€ã ã§ã¯ããã°ãã°äŸå€ã¯ã¿ããŒãšèŠãªãããŸãã å®éãäŸå€ã¯çŽç²æ§ã«éåãããããå¿
ãããæ©èœçã«çŽç²ã§ã¯ãªããšèããæ¹ãå®å
šã§ãã ããããªãããããã¯ãã³ãŒããå®è¡ããå¿
èŠãããå Žæã®çŸå®ãšãã©ã³ã¿ã€ã ãšã©ãŒãçºçããå¯èœæ§ãããããšãç¡èŠããŠããŸãã äžè¬ã«ã¯ãæãŸãããªãåé¡ãæå°éã«æããããã«ãã»ãšãã©ã®ãã®ãçŽç²ã§ãå®å
šã§ããªãããšãåæãšããŠã³ãŒããèšè¿°ããŸã (C# ã®ç©ºã® catch ãã¹ã¿ã㯠ãã¬ãŒã¹ã®èª€ã£ã管çãæ
å ±ã®ç Žæ£ãšåæ§)ã
.NET ã©ã³ã¿ã€ã ã§ã®é¢é£æ§ãšåŠ¥åœæ§ãããã³èšèªéã®ãšã³ã·ã¹ãã å šäœã«é¢ããŠã次ã®ããã«äŸå€ã®äž»èŠãªé·æãåŽé¢ãèæ ®ããããšãéèŠã§ãã
- 詳现ãªèšºææ å ±ãå«ãŸããŠãããåé¡ããããã°ãããšãã«äŸ¿å©ã§ãã
- ã©ã³ã¿ã€ã ããã®ä»ã® .NET èšèªã«ãã£ãŠããçè§£ãããŠããŸãã
- ã»ãã³ãã£ã¯ã¹ã®ãµãã»ãããã¢ããã㯠ããŒã¹ã§å®è£ ããããšã«ãã£ãŠæ æã«äŸå€ã "åé¿" ããã³ãŒããšæ¯èŒãããšãéèŠãªå®åå¥ãæžããããšãã§ããŸãã
ãã® 3 çªç®ã®ãã€ã³ãã¯éèŠã§ãã è€éãªæäœã®å ŽåãäŸå€ã䜿çšããªããšã次ã®ãããªæ§é äœãåŠçãããå¯èœæ§ããããŸãã
Result<Result<MyType, string>, string list>
ããã¯ã"æååã§åæå®ããã" ãšã©ãŒã§ã®ãã¿ãŒã³ ãããã³ã°ã®ãããªè匱ãªã³ãŒãã«ã€ãªããå¯èœæ§ããããŸãã
let result = doStuff()
match result with
| Ok r -> ...
| Error e ->
if e.Contains "Error string 1" then ...
elif e.Contains "Error string 2" then ...
else ... // Who knows?
ããã«ã次ã®ãã㪠"ããè¯ã" åãè¿ã "åçŽãª" 颿°ãåžæããå Žåã«ã¯ãäŸå€ã飲ã¿èŸŒã¿ãããªããŸãã
// Can be problematic due to discarding the cause of error.
let tryReadAllText (path : string) =
try System.IO.File.ReadAllText path |> Some
with _ -> None
æ®å¿µãªãããtryReadAllText ã¯ããã¡ã€ã« ã·ã¹ãã ã§çºçããå¯èœæ§ã®ãããããããã®ã«åºã¥ããŠå€æ°ã®äŸå€ãã¹ããŒããããšããããŸãããã®ã³ãŒãã§ã¯ãç°å¢ã§å®éã«çºçããåé¡ã«é¢ããæ
å ±ãç Žæ£ãããŸãã ãã®ã³ãŒããçµæã®åã«çœ®ãæãããšã次ã®ãã㪠"æååã§åæå®ããã" ãšã©ãŒ ã¡ãã»ãŒãžã®è§£æã«æ»ããŸãã
// Problematic, callers only have a string to figure the cause of error.
let tryReadAllText (path : string) =
try System.IO.File.ReadAllText path |> Ok
with e -> Error e.Message
let r = tryReadAllText "path-to-file"
match r with
| Ok text -> ...
| Error e ->
if e.Contains "uh oh, here we go again..." then ...
else ...
ãŸããäŸå€ãªããžã§ã¯ãèªäœã Error ã³ã³ã¹ãã©ã¯ã¿ãŒã«é
眮ããŠãã颿°ã§ã¯ãªããåŒã³åºããµã€ãã§äŸå€ã®åãé©åã«åŠçããããã«åŒ·å¶ãããã ãã§ãã ããã«ãã£ãŠãäºå®äžããã§ãã¯ãããäŸå€ãäœæãããŸããããã¯ãAPI ã®åŒã³åºãå
ãšããŠå¯Ÿå¿ããã®ã¯æ¥œãããã®ã§ãªãããšãåšç¥ãããŠããŸãã
äžèšã®äŸã®ä»£ããã«ã"ç¹å®ã®" äŸå€ããã£ãããããã®äŸå€ã®ã³ã³ããã¹ãã§æå³ã®ããå€ãè¿ãæ¹æ³ããããŸãã
tryReadAllText 颿°ã次ã®ããã«å€æŽãããšãNone ã®æå³ã倧ãããªããŸãã
let tryReadAllTextIfPresent (path : string) =
try System.IO.File.ReadAllText path |> Some
with :? FileNotFoundException -> None
ãã®é¢æ°ã¯ããã£ãããªãŒã«ãšããŠæ©èœããã®ã§ã¯ãªãããã¡ã€ã«ãèŠã€ãããªãã£ãå Žåãé©åã«åŠçãããã®æå³ãæ»ãå€ã«å²ãåœãŠãããã«ãªããŸããã ãã®æ»ãå€ã¯ãã®ãšã©ãŒ ã±ãŒã¹ã«ãããã§ããŸãããã³ã³ããã¹ãæ å ±ãç Žæ£ããããã³ãŒãå ã®ãã®æç¹ã§é¢é£ããªãå¯èœæ§ã®ããã±ãŒã¹ãåŒã³åºãå ã«åŠçããããããããšã¯ãããŸããã
Result<'Success, 'Error> ãªã©ã®åã¯ãå
¥ãåã«ãªã£ãŠããªãåºæ¬æäœã«é©ããŠããŸãããŸããF# ã®ãªãã·ã§ã³ã®åã¯ã"äœã" ãè¿ãã "äœã" è¿ããªããã®ããããã§ããå Žåã衚ãã®ã«æé©ã§ãã ãã ãããããã¯äŸå€ã®ä»£ããã«ã¯ãªããªãã®ã§ãäŸå€ã眮æããããã«ã¯äœ¿çšããªãã§ãã ããã 代ããã«ãå¯Ÿè±¡ã®æ¹æ³ã§äŸå€ããã³ãšã©ãŒç®¡çããªã·ãŒã®ç¹å®ã®åŽé¢ã«å¯ŸåŠããããã«ãæ
éã«é©çšããå¿
èŠããããŸãã
éšåé©çšãšãã€ã³ãããªãŒ ããã°ã©ãã³ã°
F# ã§ã¯éšåçãªã¢ããªã±ãŒã·ã§ã³ããµããŒãããŠããããããã€ã³ãããªãŒ ã¹ã¿ã€ã«ã§ããã°ã©ãã³ã°ããããŸããŸãªæ¹æ³ããµããŒããããŠããŸãã ããã¯ãã¢ãžã¥ãŒã«å ã§ã®ã³ãŒãã®åå©çšãäœããã®å®è£ ã«åœ¹ç«ã€å ŽåããããŸããããããªãã¯ã«å ¬éãããã®ã§ã¯ãããŸããã äžè¬ã«ããã€ã³ãããªãŒ ããã°ã©ãã³ã°èªäœã¯çŸåŸ³ã§ã¯ãããŸããããŸãããã®ã¹ã¿ã€ã«ã«æ²¡é ããŠããªã人ã«ãšã£ãŠã¯ãé倧ãªèªç¥ã®å£ã«ãªãå¯èœæ§ããããŸãã
å ¬é API ã§éšåé©çšãšã«ãªãŒåã䜿çšããªã
äŸå€ãã»ãšãã©ãªãå Žåããããªã㯠API ã§éšåçãªã¢ããªã±ãŒã·ã§ã³ã䜿çšãããšãã³ã³ã·ã¥ãŒããŒã«ãšã£ãŠæ··ä¹±ãæãå¯èœæ§ããããŸãã F# ã³ãŒãã§ã¯éåžžãlet ã§ãã€ã³ããããå€ã¯ã颿°å€ã§ã¯ãªãå€ã§ãã å€ãšé¢æ°å€ãæ··åšããããšãç¹ã«>>ã®ãããªæŒç®åã䜿ã£ãŠé¢æ°ãæ§æããå Žåãã³ãŒãã®è¡æ°ãå°ãã ãæžãããŸããããã®ä»£ããã«ããªãã®èªç¥çè² è·ãæãå¯èœæ§ããããŸãã
ãã€ã³ãããªãŒ ããã°ã©ãã³ã°ãžã®ããŒã«ã®åœ±é¿ã«ã€ããŠæ€èšãã
ã«ãªãŒå颿°ã§ã¯ãåŒæ°ã«ã©ãã«ã¯ä»ããããŸããã ããã«ã¯ãããŒã«ã«å¯Ÿãã圱é¿ããããŸãã æ¬¡ã® 2 ã€ã®é¢æ°ã«ã€ããŠèããŠã¿ãŸãã
let func name age =
printfn $"My name is {name} and I am %d{age} years old!"
let funcWithApplication =
printfn "My name is %s and I am %d years old!"
ã©ã¡ããæå¹ãªé¢æ°ã§ãããfuncWithApplication ã¯ã«ãªãŒå颿°ã§ãã ãšãã£ã¿ãŒã§ãã®åã«ããŠã¹ ãã€ã³ã¿ãŒãåããããšã次ã®ããã«è¡šç€ºãããŸãã
val func : name:string -> age:int -> unit
val funcWithApplication : (string -> int -> unit)
åŒã³åºããµã€ãã§ã¯ãVisual Studio ãªã©ã®ããŒã«ã®ããŒã«ãã³ãã«ãã£ãŠåã·ã°ããã£ãæäŸãããŸãããååãå®çŸ©ãããŠããªããããååã¯è¡šç€ºãããŸããã ååã¯åŒã³åºãå ã API ã®èåŸã«ããæå³ãããæ·±ãçè§£ããã®ã«åœ¹ç«ã€ãããåªãã API èšèšã«äžå¯æ¬ ã§ãã ãããªã㯠API ã§ãã€ã³ãããªãŒ ã³ãŒãã䜿çšãããšãåŒã³åºãå ãçè§£ãã¥ãããªãå¯èœæ§ããããŸãã
ãããªãã¯ã«äœ¿çšã§ãã funcWithApplication ã®ãããªãã€ã³ãããªãŒã®ã³ãŒãããã£ãå Žåã¯ãå®å
šãª η-å±éãå®è¡ããããšããå§ãããŸããããã«ãããããŒã«ãåŒæ°ã®æå³ã®ããååãååŸã§ããããã«ãªããŸãã
ããã«ããã€ã³ãããªãŒã®ã³ãŒãã®ãããã°ã¯ãäžå¯èœã§ã¯ãªãã«ããŠããå°é£ãªå ŽåããããŸãã ãããã° ããŒã«ã¯ãååã«ãã€ã³ããããå€ (ããšãã°ãlet ã§ã®ãã€ã³ã) ã«äŸåããŠããã®ã§ãå®è¡ã®éäžã§äžéå€ãæ€æ»ã§ããŸãã ã³ãŒãã«æ€æ»ããå€ããªãå Žåããããã°ãããã®ã¯ãããŸããã å°æ¥çã«ã¯ããããã° ããŒã«ã¯ã以åã«å®è¡ããããã¹ã«åºã¥ããŠãããã®å€ãåæããããã«çºå±ããå¯èœæ§ããããŸããã"æœåšçãª" ãããã°æ©èœã«è³ããã®ã¯åŸçã§ã¯ãããŸããã
å éšã®å®åå¥ãæžããããã®ææ³ãšããŠéšåçãªã¢ããªã±ãŒã·ã§ã³ãæ€èšãã
åã®ç¹ãšã¯å¯Ÿç §çã«ãéšåçãªã¢ããªã±ãŒã·ã§ã³ã¯ãã¢ããªã±ãŒã·ã§ã³å ã®å®åå¥ãŸã㯠API ã®æ·±ãå éšæ§é ãæžããããã®åªããããŒã«ã§ãã ããã¯ããã°ãã°å®åçãªåŠçãé¢åã«ãªããããè€é㪠API ã®å®è£ ã®åäœãã¹ããè¡ãã®ã«äŸ¿å©ã§ãã ããšãã°ã次ã®ã³ãŒãã¯ããã®ãããªãã¬ãŒã ã¯ãŒã¯ã«å€éšäŸåé¢ä¿ãæãããé¢é£ããç¹æ³šã® API ãç¿åŸããããšãªããã»ãšãã©ã®ã¢ã㯠ãã¬ãŒã ã¯ãŒã¯ã§æäŸãããæ©èœãå®çŸããæ¹æ³ã瀺ããŠããŸãã
ããšãã°ã次ã®ãœãªã¥ãŒã·ã§ã³ ããã°ã©ãã£ãèããŠã¿ãŸãã
MySolution.sln
|_/ImplementationLogic.fsproj
|_/ImplementationLogic.Tests.fsproj
|_/API.fsproj
ImplementationLogic.fsproj ã§ã¯ã次ã®ãããªã³ãŒããå
¬éãããå ŽåããããŸãã
module Transactions =
let doTransaction txnContext txnType balance =
...
type Transactor(ctx, currentBalance) =
member _.ExecuteTransaction(txnType) =
Transactions.doTransaction ctx txnType currentBalance
...
Transactions.doTransaction ã§ã® ImplementationLogic.Tests.fsproj ã®åäœãã¹ãã¯ç°¡åã§ãã
namespace TransactionsTestingUtil
open Transactions
module TransactionsTestable =
let getTestableTransactionRoutine mockContext = Transactions.doTransaction mockContext
ã¢ã㯠ã³ã³ããã¹ã ãªããžã§ã¯ãã§ doTransaction ãéšåçã«é©çšãããšãæ¯åã¢ã㯠ã³ã³ããã¹ããæ§ç¯ããªããŠãããã¹ãŠã®åäœãã¹ãã§é¢æ°ãåŒã³åºãããšãã§ããŸãã
module TransactionTests
open Xunit
open TransactionTypes
open TransactionsTestingUtil
open TransactionsTestingUtil.TransactionsTestable
let testableContext =
{ new ITransactionContext with
member _.TheFirstMember() = ...
member _.TheSecondMember() = ... }
let transactionRoutine = getTestableTransactionRoutine testableContext
[<Fact>]
let ``Test withdrawal transaction with 0.0 for balance``() =
let expected = ...
let actual = transactionRoutine TransactionType.Withdraw 0.0
Assert.Equal(expected, actual)
ãã®ææ³ãã³ãŒãããŒã¹å šäœã«å¯ŸããŠæ±çšçã«é©çšããªãã§ãã ããããã ããè€éãªå éšæ§é ããã³ãããã®å éšã®åäœãã¹ãã®ããã«å®åå¥ãæžããã«ã¯ããæ¹æ³ã§ãã
ã¢ã¯ã»ã¹å¶åŸ¡
F# ã«ã¯ã.NET ã©ã³ã¿ã€ã ã§äœ¿çšã§ãããã®ããç¶æ¿ãããã¢ã¯ã»ã¹å¶åŸ¡ã®ããã®ãªãã·ã§ã³ãè€æ°ãããŸãã ãããã¯ãåã ãã§ãªãã颿°ã«ã䜿çšã§ããŸãã
åºã䜿çšãããŠãããã©ã€ãã©ãªã®ã³ã³ããã¹ãã§ã®é©åãªãã©ã¯ãã£ã¹:
- ãããªãã¯ã«äœ¿çšã§ããããã«ããå¿
èŠããªããã°ã
publicã§ãªãåãšã¡ã³ããŒãåªå ããŸãã ããã«ãããã³ã³ã·ã¥ãŒããŒãé¢é£ã¥ãããã®ãæå°éã«æããããšãã§ããŸãã - ãã¹ãŠã®ãã«ããŒæ©èœã
privateã«ããããåªåããŠãã ããã - ãã«ããŒé¢æ°ã倿°ã«ãªãå Žåã¯ããã«ããŒé¢æ°ã®ãã©ã€ããŒã ã¢ãžã¥ãŒã«ã§
[<AutoOpen>]ã䜿çšããããšãæ€èšããŠãã ããã
åæšè«ãšãžã§ããªãã¯
åæšè«ã«ãã£ãŠã倧éã®å®åå¥ã®å ¥åãçç¥ããããšãã§ããŸãã ãŸããF# ã³ã³ãã€ã©ã®èªåãžã§ããªãã¯åã¯ã远å ã®äœæ¥ãã»ãšãã©å¿ èŠãšããã«ãããæ±çšçãªã³ãŒããäœæããã®ã«åœ¹ç«ã¡ãŸãã ãã ãããããã®æ©èœã¯ãå šè¬çã«è¯å¥œãªãã®ã§ã¯ãããŸããã
ãããªã㯠API ã§ã¯æç€ºçãªåã䜿çšããŠåŒæ°åã«ã©ãã«ãä»ããããšãæ€èšãããã®ããã«åæšè«ã«é Œããªãã§ãã ããã
ãã®çç±ã¯ãAPI ã®æ§é ã¯ã³ã³ãã€ã©ã§ã¯ãªãèªåã§å¶åŸ¡ããå¿ èŠãããããã§ãã ã³ã³ãã€ã©ã¯åæšè«ãé©åã«å®è¡ã§ããŸãããäŸåããŠããå éšæ§é ã§åã倿Žãããå Žåã¯ãAPI ã®æ§é ã倿Žãããå¯èœæ§ããããŸãã ããã¯åžæã©ããã§ããããšããããŸãããã»ãšãã©ã®å Žåã« API ã®ç Žå£ç倿Žãè¡ãããããŠã³ã¹ããªãŒã ã®ã³ã³ã·ã¥ãŒããŒã察åŠããå¿ èŠããããŸãã 代ããã«ããããªã㯠API ã®æ§é ãæç€ºçã«å¶åŸ¡ããå Žåã¯ããããã®ç Žå£ç倿Žãå¶åŸ¡ã§ããŸãã DDD ã®çšèªã§ã¯ãããã¯ç Žæå¯Ÿçã¬ã€ã€ãŒãšèããããšãã§ããŸãã
æ±çšåŒæ°ã«ããããããååãä»ããããšãæ€èšããŠãã ããã
ç¹å®ã®ãã¡ã€ã³ã«åºæã§ã¯ãªãçã«æ±çšçãªã³ãŒããèšè¿°ããå Žåãé€ããããããããååãä»ããããšã§ãä»ã®ããã°ã©ããäœæ¥äžã®ãã¡ã€ã³ãçè§£ããã®ã«åœ¹ç«ã¡ãŸãã ããšãã°ãããã¥ã¡ã³ã ããŒã¿ããŒã¹ãæäœããã³ã³ããã¹ãã§
'Documentãšããååã®åãã©ã¡ãŒã¿ãŒã䜿çšãããšãäžè¬çãªããã¥ã¡ã³ãã®çš®é¡ããäœæ¥ããŠãã颿°ãŸãã¯ã¡ã³ããŒã«ãã£ãŠåãå ¥ããããããšããããããããªããŸãããžã§ããªãã¯åãã©ã¡ãŒã¿ãŒã«ã¯ããã¹ã«ã« ã±ãŒã¹ã䜿çšããŠååãä»ããããšãæ€èšããŠãã ããã
ãã㯠.NET ã§äœæ¥ãè¡ãããã®äžè¬çãªæ¹æ³ã§ãããããã¹ããŒã¯ ã±ãŒã¹ãŸãã¯ãã£ã¡ã« ã±ãŒã¹ã§ã¯ãªãããã¹ã«ã« ã±ãŒã¹ã䜿çšããããšããå§ãããŸãã
æåŸã«ãF# ãŸãã¯å€§èŠæš¡ãªã³ãŒãããŒã¹ãåããŠäœ¿çšãããŠãŒã¶ãŒã«ãšã£ãŠã¯ãèªåãžã§ããªãã¯åãåžžã«æçãªãã®ã«ãªããšã¯éããŸããã ãžã§ããªã㯠ã³ã³ããŒãã³ãã䜿çšãããšãèªèã®ãªãŒããŒããããçºçããŸãã ããã«ãèªåçã«ãžã§ããªãã¯åããã颿°ãããŸããŸãªå ¥ååã§äœ¿çšãããŠããªãå Žå (ãã®ããã«äœ¿çšããããšãæå³ããŠããå Žåã¯èšããŸã§ããªã)ããã®ãšãã«ãžã§ããªãã¯ã§ããããšã®å®éã®å©ç¹ã¯ãããŸããã èšè¿°ããŠããã³ãŒãããžã§ããªãã¯ã«ããããšã«å®éã«å©ç¹ããããã©ãããåžžã«èæ ®ããŠãã ããã
ããã©ãŒãã³ã¹
é«ãå²ãåœãŠçãæã€å°åã®åã«ã¯æ§é äœãæ€èšãã
æ§é äœ (å€åãšãåŒã°ããŸã) ã䜿çšãããšãå€ãã®å Žåããªããžã§ã¯ãã®å²ãåœãŠãåé¿ããããããäžéšã®ã³ãŒãã®ããã©ãŒãã³ã¹ãåäžããŸãã ãã ããæ§é äœãåžžã« "é«éå" ãã¿ã³ã«ãªããšã¯éããŸãããæ§é äœå ã®ããŒã¿ã®ãµã€ãºã 16 ãã€ããè¶ ããå ŽåãããŒã¿ãã³ããŒãããšãåç §åã䜿çšãããããå€ãã® CPU æéãæ¶è²»ãããå¯èœæ§ããããŸãã
æ§é äœã䜿çšãããã©ããã倿ããã«ã¯ãæ¬¡ã®æ¡ä»¶ãèæ ®ããŠãã ããã
- ããŒã¿ã®ãµã€ãºã 16 ãã€ã以äžã®å Žåã
- ãããã®åã®ã€ã³ã¹ã¿ã³ã¹ã®å€ãããå®è¡äžã®ããã°ã©ã ã®ã¡ã¢ãªã«åžžé§ããŠããå¯èœæ§ãé«ãå Žåã
æåã®æ¡ä»¶ã«åœãŠã¯ãŸãå Žåãéåžžã¯æ§é äœã䜿çšããå¿ èŠããããŸãã äž¡æ¹ãšãåœãŠã¯ãŸãå Žåã¯ãã»ãŒå¿ ãæ§é äœã䜿çšããå¿ èŠããããŸãã åã®æ¡ä»¶ã«åœãŠã¯ãŸã£ãŠããæ§é äœã®äœ¿çšã¯åç §åã䜿çšããã®ãšå€ãããªãããããã«æªããªãå ŽåããããŸãããã ãããã®ãããªå Žåã¯ãŸãã«ãããããŸããã ããããªããããã®ãããªå€æŽãè¡ãå Žåã¯åžžã«æž¬å®ããããšãéèŠã§ãããŸããä»®å®ãçŽæã«åºã¥ããŠæäœããªãã§ãã ããã
å²ãåœãŠçã®é«ãå°ããå€åãã°ã«ãŒãåããå Žåã¯ãæ§é äœã¿ãã«ãæ€èšãã
次㮠2 ã€ã®é¢æ°ã«ã€ããŠèããŠã¿ãŸãã
let rec runWithTuple t offset times =
let offsetValues x y z offset =
(x + offset, y + offset, z + offset)
if times <= 0 then
t
else
let (x, y, z) = t
let r = offsetValues x y z offset
runWithTuple r offset (times - 1)
let rec runWithStructTuple t offset times =
let offsetValues x y z offset =
struct(x + offset, y + offset, z + offset)
if times <= 0 then
t
else
let struct(x, y, z) = t
let r = offsetValues x y z offset
runWithStructTuple r offset (times - 1)
BenchmarkDotNet ã®ãããªçµ±èšãã³ãããŒã¯ ããŒã«ã䜿çšããŠãããã®é¢æ°ã®ãã³ãããŒã¯ãè¡ããšãæ§é äœã¿ãã«ã䜿çšãã runWithStructTuple 颿°ã¯ 40% é«éã«å®è¡ãããã¡ã¢ãªãå²ãåœãŠãããªãããšãããããŸãã
ãã ãããããã®çµæã¯ãå¿
ãããèªåã®ã³ãŒãã«åœãŠã¯ãŸããšã¯éããŸããã 颿°ã inline ãšããŠããŒã¯ãããšãåç
§ã¿ãã«ã䜿çšããã³ãŒãã«è¿œå ã®æé©åãè¡ãããããšããããŸãããŸããå²ãåœãŠãããã³ãŒããæé©åãããã ãã®å¯èœæ§ããããŸãã ããã©ãŒãã³ã¹ã«æžå¿µãããå Žåã¯åžžã«çµæã枬å®ããæ±ºããŠä»®å®ãçŽæã«åºã¥ããŠæäœããªãã§ãã ããã
åãå°ããå²ãåœãŠçãé«ãå Žåã¯ãæ§é äœã¬ã³ãŒããæ€èšãã
åè¿°ã®çµéšåã¯ãF# ã®ã¬ã³ãŒãåã«ã€ããŠã該åœããŸãã ããããåŠçããæ¬¡ã®ããŒã¿åãšé¢æ°ã«ã€ããŠèããŠã¿ãŸãã
type Point = { X: float; Y: float; Z: float }
[<Struct>]
type SPoint = { X: float; Y: float; Z: float }
let rec processPoint (p: Point) offset times =
let inline offsetValues (p: Point) offset =
{ p with X = p.X + offset; Y = p.Y + offset; Z = p.Z + offset }
if times <= 0 then
p
else
let r = offsetValues p offset
processPoint r offset (times - 1)
let rec processStructPoint (p: SPoint) offset times =
let inline offsetValues (p: SPoint) offset =
{ p with X = p.X + offset; Y = p.Y + offset; Z = p.Z + offset }
if times <= 0 then
p
else
let r = offsetValues p offset
processStructPoint r offset (times - 1)
ããã¯åã®ã¿ãã« ã³ãŒãã«äŒŒãŠããŸãããä»åã®äŸã§ã¯ã¬ã³ãŒããšã€ã³ã©ã€ã³å éšé¢æ°ã䜿çšããŸãã
BenchmarkDotNet ã®ãããªçµ±èšãã³ãããŒã¯ ããŒã«ã䜿çšããŠãããã®é¢æ°ã®ãã³ãããŒã¯ãè¡ããšãprocessStructPoint ã¯çŽ 60% é«éã«å®è¡ããããããŒãžã ããŒãã«ã¯äœãå²ãåœãŠãããªãããšãããããŸãã
ããŒã¿åãå°ãããå²ãåœãŠé »åºŠãé«ãå Žåã¯ãæ§é äœã䜿çšããå€å¥å ±çšäœã®å©çšãæ€èšããã
æ§é äœã¿ãã«ãšã¬ã³ãŒãã䜿çšããããã©ãŒãã³ã¹ã«é¢ãã以åã®èгå¯çµæã¯ãF# ã®å€å¥å ±çšäœã«ã€ããŠã該åœããŸãã æ¬¡ã®ã³ãŒãããããšããŸãã
type Name = Name of string
[<Struct>]
type SName = SName of string
let reverseName (Name s) =
s.ToCharArray()
|> Array.rev
|> System.String
|> Name
let structReverseName (SName s) =
s.ToCharArray()
|> Array.rev
|> System.String
|> SName
ãã¡ã€ã³ ã¢ããªã³ã°ã«ã¯ããã®ãããªåäžã±ãŒã¹ã®å€å¥å
±çšäœãå®çŸ©ããã®ãäžè¬çã§ãã
BenchmarkDotNet ã®ãããªçµ±èšãã³ãããŒã¯ ããŒã«ã䜿çšããŠãããã®é¢æ°ã®ãã³ãããŒã¯ãè¡ããšãstructReverseName ã¯å°ããæååã«å¯Ÿã㊠reverseName ãããçŽ 25% é«éã«å®è¡ãããããšãããããŸãã 倧ããªæååã®å Žåã¯ãäž¡è
ã®ããã©ãŒãã³ã¹ã¯ã»ãŒåãã§ãã ãã®ããããã®å Žåã¯ãåžžã«æ§é äœã䜿çšããããšããå§ãããŸãã åè¿°ã®ããã«ãåžžã«æž¬å®ãè¡ããä»®å®ãçŽæã«åºã¥ããŠæäœããªãã§ãã ããã
åã®äŸã§ã¯ãæ§é äœã®å€å¥å ±çšäœã§ããã©ãŒãã³ã¹ãåäžããããšã瀺ãããŸãããããã¡ã€ã³ãã¢ãã«åããå Žåã¯ããã倧ããªå€å¥å ±çšäœã䜿çšããã®ãäžè¬çã§ãã ãã®ãããªå€§èŠæš¡ãªããŒã¿åã¯ãããã«å¯Ÿããæäœã«å¿ããæ§é äœã§ããå Žåã«ã¯ãããå€ãã®ã³ããŒãé¢ä¿ããå¯èœæ§ããããããããã©ãŒãã³ã¹ãåçã«ãªããªãå¯èœæ§ããããŸãã
äžå€æ§ãšå€å
F# ã®å€ã¯ãæ¢å®ã§ã¯å€æŽã§ããŸãããããã«ãããç¹å®ã®ã¯ã©ã¹ã®ãã° (ç¹ã«åæå®è¡æ§ãšäžŠååŠçã䌎ããã®) ãåé¿ã§ããŸãã ãã ããå Žåã«ãã£ãŠã¯ãå®è¡æéãã¡ã¢ãªã®å²ãåœãŠã®å¹çãæé©å (ãŸãã¯åçå) ããããã«ãç¶æ
ã®ã€ã³ãã¬ãŒã¹å€åã䜿çšããŠäœæ¥ã®ç¯å²ãå®è£
ããããšããå§ãããŸãã ããã¯ãF# ã§ã¯ mutable ããŒã¯ãŒãã䜿çšããŠãªããã€ã³ã§ããŸãã
F# ã§ mutable ã䜿çšããããšã¯ã颿°åã®çŽç²æ§ãšççŸããŠãããšæãããããããŸããã ããã¯çè§£ã§ããŸãããããããå Žæã§æ©èœçãªçŽç²æ§ãä¿ã€ããšã¯ãããã©ãŒãã³ã¹ç®æšãšã¯çžå®¹ããªãå ŽåããããŸãã 劥åç¹ã¯ãåŒã³åºãå
ã颿°ãåŒã³åºãããšãã®åäœãæ°ã«ããå¿
èŠããªãããã«ãå€åãã«ãã»ã«åããããšã§ãã ããã«ãããããã©ãŒãã³ã¹ ã¯ãªãã£ã«ã«ãªã³ãŒãã®ããã«ã倿ŽããŒã¹ã®å®è£
ã«å¯ŸããŠæ©èœã€ã³ã¿ãŒãã§ã€ã¹ãèšè¿°ã§ããŸãã
ãŸããF# let ãã€ã³ã ã³ã³ã¹ãã©ã¯ãã䜿çšãããšããã€ã³ããå¥ã®æ§é ã«å
¥ãåã«ããããšãã§ããŸãããããå©çšããŠã mutable 倿°ã®ã¹ã³ãŒããè¿ã¥ããããçè«äžæå°ã«ä¿ã€ããšãã§ããŸãã
let data =
[
let mutable completed = false
while not completed do
logic ()
// ...
if someCondition then
completed <- true
]
ã©ã®ã³ãŒãããcompleted let ã§ãã€ã³ããããå€ã®åæåã®ã¿ã«äœ¿çšããã倿Žå¯èœãª data ã«ã¯ã¢ã¯ã»ã¹ã§ããŸããã
äžå€ã®ã€ã³ã¿ãŒãã§ãŒã¹ã§å€æŽå¯èœãªã³ãŒããã©ãããã
åç
§ã®ééæ§ãç®æšãšããŠãããã©ãŒãã³ã¹ ã¯ãªãã£ã«ã«ãªé¢æ°ã®å€æŽå¯èœãªåŒ±ç¹ãå
¬éããªãã³ãŒããèšè¿°ããããšãéèŠã§ãã ããšãã°ã次ã®ã³ãŒãã§ã¯ãF# ã³ã¢ ã©ã€ãã©ãªã® Array.contains 颿°ãå®è£
ããŠããŸãã
[<CompiledName("Contains")>]
let inline contains value (array:'T[]) =
checkNonNull "array" array
let mutable state = false
let mutable i = 0
while not state && i < array.Length do
state <- value = array[i]
i <- i + 1
state
ãã®é¢æ°ãè€æ°ååŒã³åºããŠããåºã«ãªãé åã倿Žãããããšã¯ãããŸããããŸãã䜿çšäžã«å€æŽå¯èœãªç¶æ ãç¶æããå¿ èŠããããŸããã ããšããã®äžã®ã»ãŒãã¹ãŠã®ã³ãŒãè¡ã§ãã¥ãŒããŒã·ã§ã³ã䜿ãããŠããŠããåç §ééæ§ãæã£ãŠããŸãã
倿Žå¯èœãªããŒã¿ãã¯ã©ã¹ã«ã«ãã»ã«åããããšãæ€èšãã
åã®äŸã§ã¯ã倿Žå¯èœãªããŒã¿ã䜿çšããŠæäœãã«ãã»ã«åããããã«åäžã®é¢æ°ã䜿çšããŸããã ããã¯ãããè€éãªããŒã¿ ã»ããã«ã¯å¿ ãããååã§ã¯ãããŸããã æ¬¡ã®äžé£ã®é¢æ°ã«ã€ããŠèããŠã¿ãŸãã
open System.Collections.Generic
let addToClosureTable (key, value) (t: Dictionary<_,_>) =
if t.ContainsKey(key) then
t[key] <- value
else
t.Add(key, value)
let closureTableCount (t: Dictionary<_,_>) = t.Count
let closureTableContains (key, value) (t: Dictionary<_, HashSet<_>>) =
match t.TryGetValue(key) with
| (true, v) -> v.Equals(value)
| (false, _) -> false
ãã®ã³ãŒãã¯ããã©ãŒãã³ã¹ã«åªããŠããŸãããåŒã³åºãå ãä¿æãã倿ŽããŒã¹ã®ããŒã¿æ§é ãå ¬éããŠããŸãã ããã¯ã次ã®ããã«ãåºã«ãªã倿Žå¯èœãªã¡ã³ããŒãæããªãã¯ã©ã¹ã®å éšã«ã©ããã§ããŸãã
open System.Collections.Generic
/// The results of computing the LALR(1) closure of an LR(0) kernel
type Closure1Table() =
let t = Dictionary<Item0, HashSet<TerminalIndex>>()
member _.Add(key, value) =
if t.ContainsKey(key) then
t[key] <- value
else
t.Add(key, value)
member _.Count = t.Count
member _.Contains(key, value) =
match t.TryGetValue(key) with
| (true, v) -> v.Equals(value)
| (false, _) -> false
Closure1Table ã§ã¯ãåºã«ãªã倿ŽããŒã¹ã®ããŒã¿æ§é ãã«ãã»ã«åããåŒã³åºãå
ãåºã«ãªãããŒã¿æ§é ãç¶æããããšã匷å¶ããŸããã ã¯ã©ã¹ã¯ãåŒã³åºãå
ã«è©³çްæ
å ±ãå
¬éããã«ã倿ŽããŒã¹ã®ããŒã¿ãšã«ãŒãã³ãã«ãã»ã«åããããã®åŒ·åãªæ¹æ³ã§ãã
let mutable ããã ref ãåªå
ãã
åç §ã»ã«ã¯ãå€èªäœã§ã¯ãªããå€ãžã®åç §ãè¡šãæ¹æ³ã§ãã ããã©ãŒãã³ã¹ ã¯ãªãã£ã«ã«ãªã³ãŒãã«ã¯äœ¿çšã§ããŸãããæšå¥šãããŸããã æ¬¡ã®äŸã確èªããŠãã ããã
let kernels =
let acc = ref Set.empty
processWorkList startKernels (fun kernel ->
if not ((!acc).Contains(kernel)) then
acc := (!acc).Add(kernel)
...)
!acc |> Seq.toList
åç
§ã»ã«ã䜿çšãããšãåŸç¶ã®ãã¹ãŠã®ã³ãŒãã§ãåºã«ãªãããŒã¿ãéåç
§ããŠååç
§ããå¿
èŠãããããšã "æ±æ" ã«ãªããŸãã 代ããã«ãlet mutable ãæ€èšããŠãã ããã
let kernels =
let mutable acc = Set.empty
processWorkList startKernels (fun kernel ->
if not (acc.Contains(kernel)) then
acc <- acc.Add(kernel)
...)
acc |> Seq.toList
ã©ã ãåŒã®éäžã«ããåäžã®å€åã®ãã€ã³ããé€ããŠãacc ã«è§Šããä»ã®ãã¹ãŠã®ã³ãŒãã¯ãéåžžã® let ã§ãã€ã³ãããã倿Žã§ããªãå€ã®äœ¿çšãšå€ãããªãæ¹æ³ã§å®è¡ã§ããŸãã ããã«ãããæéã®çµéãšå
±ã«ç°¡åã«å€æŽã§ããããã«ãªããŸãã
null ãšæ¢å®å€
éåžžãF# ã§ã¯ null ãé¿ããå¿
èŠããããŸãã æ¢å®ã§ã¯ãF# ã§å®£èšãããå㯠null ãªãã©ã«ã®äœ¿çšããµããŒãããããã¹ãŠã®å€ãšãªããžã§ã¯ããåæåãããŸãã ããããäžè¬ç㪠.NET API ã®äžã«ã¯ãnull ãè¿ããåãå
¥ãããã®ããããé
åãæååãªã©ã®äžè¬ç㪠.NET ã§å®£èšãããåã®äžã«ã¯ãnull ãèš±å¯ããããã®ããããŸãã ãã ããF# ããã°ã©ãã³ã°ã§ã¯ null å€ã®åºçŸã¯éåžžã«ãŸãã§ãããF# ã䜿çšããå©ç¹ã® 1 ã€ã¯ãã»ãšãã©ã®å Žåãnull åç
§ãšã©ãŒãåé¿ãããããšã§ãã
AllowNullLiteral 屿§ã®äœ¿çšãé¿ãã
æ¢å®ã§ã¯ãF# ã§å®£èšãããå㯠null ãªãã©ã«ã®äœ¿çšããµããŒãããŠããŸããã ãããå¯èœã«ããããã«ãæåã§ F# åã« AllowNullLiteral ã®æ³šéãä»ããããšãã§ããŸãã ãã ããã»ãšãã©ã®å Žåã¯ããããè¡ããªãããšããå§ãããŸãã
Unchecked.defaultof<_> 屿§ã®äœ¿çšãé¿ãã
F# åã® Unchecked.defaultof<_> ãŸãã¯ãŒãã§åæåãããå€ããnull ã䜿çšããŠçæã§ããŸãã ããã¯ãäžéšã®ããŒã¿æ§é ã®ã¹ãã¬ãŒãžãåæåããå Žåããããã©ãŒãã³ã¹ã®é«ãã³ãŒãã£ã³ã° ãã¿ãŒã³ããŸãã¯çžäºéçšæ§ãå®çŸããå Žåã«åœ¹ç«ã¡ãŸãã ãã ãããã®ã³ã³ã¹ãã©ã¯ãã®äœ¿çšã¯é¿ããå¿
èŠããããŸãã
DefaultValue 屿§ã®äœ¿çšãé¿ãã
æ¢å®ã§ã¯ãF# ã®ã¬ã³ãŒããšãªããžã§ã¯ãã¯æ§ç¯æã«é©åã«åæåããå¿
èŠããããŸãã
DefaultValue 屿§ã䜿çšãããšããªããžã§ã¯ãã®äžéšã®ãã£ãŒã«ãã«ãnull ãŸãã¯ãŒãã§åæåãããå€ãèšå®ã§ããŸãã ãã®ã³ã³ã¹ãã©ã¯ãã¯ãã£ãã«å¿
èŠãšãããªãã®ã§ããã®äœ¿çšã¯é¿ããå¿
èŠããããŸãã
null ã®å ¥åã確èªããå Žåã¯ãæ©ãæ©äŒã«äŸå€ãçºçããã
æ°ãã F# ã³ãŒããèšè¿°ããå ŽåãC# ããã®ä»ã® .NET èšèªãããã®ã³ãŒãã䜿çšãããããšãèŠèŸŒãŸããªãéããå®éã«ã¯ null å ¥åã確èªããå¿ èŠã¯ãããŸããã
null å ¥åã®ãã§ãã¯ã远å ããå Žåã¯ãæ©ãæ©äŒã«ãã§ãã¯ãå®è¡ããäŸå€ãçºçãããŸãã æ¬¡ã«äŸã瀺ããŸãã
let inline checkNonNull argName arg =
if isNull arg then
nullArg argName
module Array =
let contains value (array:'T[]) =
checkNonNull "array" array
let mutable result = false
let mutable i = 0
while not state && i < array.Length do
result <- value = array[i]
i <- i + 1
result
åŸæ¥ã®çç±ãããFSharp.Core ã®äžéšã®æåå颿°ã§ã¯åŒãç¶ã null ãç©ºã®æååãšããŠæ±ããnull åŒæ°ã§ã¯å€±æããŸããã ãã ããããã¯ã¬ã€ãã³ã¹ãšããŠåãåãããã»ãã³ãã£ãã¯ã®æå³ããã¹ãŠ "null" ã«çµã³ä»ããã³ãŒãã£ã³ã° ãã¿ãŒã³ã¯æ¡çšããªãã§ãã ããã
API ã®å¢çã§ F# 9 null æ§æãæŽ»çšãã
F# 9 ã§ã¯ãæ§æ ã远å ããŠãå€ã null ã«ã§ããããšãæç€ºçã«ç€ºããŸãã ããã¯ãNULL åŠçãæ¬ èœããŠããå Žæãã³ã³ãã€ã©ã«ç€ºãããã«ãAPI ã®å¢çã§äœ¿çšãããããã«èšèšãããŠããŸãã
æ§æã®æå¹ãªäœ¿ç𿹿³ã®äŸã次ã«ç€ºããŸãã
type CustomType(m1, m2) =
member _.M1 = m1
member _.M2 = m2
override this.Equals(obj: obj | null) =
match obj with
| :? CustomType as other -> this.M1 = other.M1 && this.M2 = other.M2
| _ -> false
override this.GetHashCode() =
hash (this.M1, this.M2)
F# ã³ãŒãã®äžã§ null ãããã«æ¡æ£ããªãããã«é¿ããŠãã ããã
let getLineFromStream (stream: System.IO.StreamReader) : string | null =
stream.ReadLine()
代ããã«ãæ £çš F# ã®ææ®µ (ãªãã·ã§ã³ãªã©) ã䜿çšããŸãã
let getLineFromStream (stream: System.IO.StreamReader) =
stream.ReadLine() |> Option.ofObj
null é¢é£ã®äŸå€ãçºçãããå Žåã¯ãç¹æ®ãª nullArgCheck 颿°ãš nonNull 颿°ã䜿çšã§ããŸãã ãŸããå€ã null ã§ãªãå Žåã¯ããµãã¿ã€ãºãããå€ãæã€åŒæ°ã ã·ã£ã㊠ããããã䟿å©ã§ãããã以äžã®ã³ãŒãã§ã¯ãå¯èœãª null ãã€ã³ã¿ãŒã«ã¢ã¯ã»ã¹ã§ããªããªããŸãã
let inline processNullableList list =
let list = nullArgCheck (nameof list) list // throws `ArgumentNullException`
// 'list' is safe to use from now on
list |> List.distinct
let inline processNullableList' list =
let list = nonNull list // throws `NullReferenceException`
// 'list' is safe to use from now on
list |> List.distinct
ãªããžã§ã¯ã ããã°ã©ãã³ã°
F# ã§ã¯ããªããžã§ã¯ããšãªããžã§ã¯ãæå (OO) ã®æŠå¿µãå®å šã«ãµããŒããããŠããŸãã OO ã®å€ãã®æŠå¿µã¯åŒ·åã§äŸ¿å©ã§ããããã¹ãŠã®æŠå¿µã䜿çšããã®ãçæ³çã§ãããšã¯éããŸããã æ¬¡ã®äžèЧã¯ãOO ã®ç¹åŸŽã®å€§ãŸããªã«ããŽãªã«é¢ããã¬ã€ãã³ã¹ãæäŸããŸãã
ããŸããŸãªç¶æ³ã§æ¬¡ã®æ©èœã䜿çšããããšãæ€èšããŠãã ããã
- ãããè¡šèš (
x.Length) - ã€ã³ã¹ã¿ã³ã¹ ã¡ã³ããŒ
- æé»çãªã³ã³ã¹ãã©ã¯ã¿ãŒ
- éçã¡ã³ããŒ
-
arr[x]ããããã£ãå®çŸ©ããŠã®ã€ã³ãã¯ãµãŒè¡šèš (Item) -
arr[x..y]ã¡ã³ããŒãå®çŸ©ããŠã®ã¹ã©ã€ã¹è¡šèš (arr[x..]ãarr[..y]ãGetSlice) - ååä»ãåŒæ°ãšçç¥å¯èœãªåŒæ°
- ã€ã³ã¿ãŒãã§ã€ã¹ãšã€ã³ã¿ãŒãã§ã€ã¹ã®å®è£
æ¬¡ã®æ©èœã«ã€ããŠã¯çã£å ã«äœ¿çšããªãã§ãã ãããåé¡ã解決ããã®ã«äŸ¿å©ãªå Žåã¯ãæ éã«é©çšããŠãã ããã
- ã¡ãœããã®ãªãŒããŒããŒã
- 倿Žå¯èœãªããŒã¿ã®ã«ãã»ã«å
- åã®æŒç®å
- èªåããããã£
-
IDisposableãšIEnumerableã®å®è£ - åæ¡åŒµ
- ã€ãã³ã
- æ§é äœ
- ããªã²ãŒã
- åæå
äžè¬ã«ãæ¬¡ã®æ©èœã¯ã䜿çšããå¿ èŠãããå Žåãé€ããŠé¿ããŠãã ããã
- ç¶æ¿ã«åºã¥ãåã®éå±€ãšå®è£ ã®ç¶æ¿
- Null ãš
Unchecked.defaultof<_>
ç¶æ¿ããã³ã³ããžã·ã§ã³ãåªå ãã
ãã³ã³ããžã·ã§ã³ãç¶æ¿ããåªå ããããšãã¯ãåªãã F# ã³ãŒããé·å¹Žã«ããã£ãŠéµå®ã§ããæ £çšå¥ã§ãã åºæ¬ååã¯ãåºåºã¯ã©ã¹ãå ¬éããªãããšã§ãåŒã³åºãå ããã®åºåºã¯ã©ã¹ããç¶æ¿ããã«æ©èœãååŸã§ããããã«ããããšã§ãã
ã¯ã©ã¹ãäžèŠãªå Žåã¯ããªããžã§ã¯ãåŒã䜿çšããŠã€ã³ã¿ãŒãã§ã€ã¹ãå®è£ ãã
ãªããžã§ã¯ãåŒã䜿çšãããšãã€ã³ã¿ãŒãã§ã€ã¹ãå®è¡äžã«å®è£ ããå®è£ ãããã€ã³ã¿ãŒãã§ã€ã¹ãå€ã«ãã€ã³ãã§ããŸãããããã¯ã©ã¹å ã§è¡ãå¿ èŠã¯ãããŸããã ããã¯ç¹ã«ãã€ã³ã¿ãŒãã§ã€ã¹ "ã®ã¿" ãå®è£ ããå¿ èŠããããå®å šãªã¯ã©ã¹ãå¿ èŠãšããªãå Žåã«äŸ¿å©ã§ãã
ããšãã°ãããã«ç€ºãã®ã¯ãIonideã§å®è¡ãããã³ãŒãã§ã
let private createProvider () =
{ new CodeActionProvider with
member this.provideCodeActions(doc, range, context, ct) =
let diagnostics = context.diagnostics
let diagnostic = diagnostics |> Seq.tryFind (fun d -> d.message.Contains "Unused open statement")
let res =
match diagnostic with
| None -> [||]
| Some d ->
let line = doc.lineAt d.range.start.line
let cmd = createEmpty<Command>
cmd.title <- "Remove unused open"
cmd.command <- "fsharp.unusedOpenFix"
cmd.arguments <- Some ([| doc |> unbox; line.range |> unbox; |] |> ResizeArray)
[|cmd |]
res
|> ResizeArray
|> U2.Case1
}
Visual Studio Code API ãæäœãããšãã«ã¯ã¯ã©ã¹ã¯äžèŠã§ããããããªããžã§ã¯ãåŒã¯ãã®ããã®æé©ãªããŒã«ã§ãã ãŸãããã¹ã ã«ãŒãã³ã䜿çšããŠã€ã³ã¿ãŒãã§ã€ã¹ãå³åžã§ã¹ã¿ãããå¿ èŠãããå Žåã«ãåäœãã¹ãã«ã圹ç«ã¡ãŸãã
ã·ã°ããã£ãççž®ããããã«åç¥ç§°ãæ€èšãã
åç¥ç§°ã¯ã颿°ã·ã°ããã£ãããè€éãªåãªã©ãã©ãã«ãå¥ã®åã«å²ãåœãŠãã®ã«äŸ¿å©ãªæ¹æ³ã§ãã ããšãã°ã次ã®å¥åã¯ããã£ãŒã ã©ãŒãã³ã° ã©ã€ãã©ãªã§ãã CNTK ã§èšç®ãå®çŸ©ããããã«å¿ èŠãªã©ãã«ãå²ãåœãŠãŸãã
open CNTK
// DeviceDescriptor, Variable, and Function all come from CNTK
type Computation = DeviceDescriptor -> Variable -> Function
åå Computation ã¯ããšã€ãªã¢ã¹ãšããŠäœ¿ã£ãŠããã·ã°ããã£ã«äžèŽããä»»æã®é¢æ°ã瀺ã䟿å©ãªæ¹æ³ã§ãã ãã®ãããªåç¥ç§°ã䜿çšãããšäŸ¿å©ã§ãããç°¡æœãªã³ãŒããèšè¿°ã§ããŸãã
ãã¡ã€ã³ã衚ãããã«åç¥ç§°ã䜿çšããªã
åç¥ç§°ã¯é¢æ°ã·ã°ããã£ã«ååãä»ããå Žåã«äŸ¿å©ã§ãããä»ã®åãçç¥ãããšæ··ä¹±ãæãå¯èœæ§ããããŸãã æ¬¡ã®ç¥ç§°ãèããŠã¿ãŸãã
// Does not actually abstract integers.
type BufferSize = int
ããã¯ããŸããŸãªæå³ã§æ··ä¹±ãæãå¯èœæ§ããããŸãã
-
BufferSizeã¯æœè±¡åã§ã¯ãªããæŽæ°ã®å¥ã®ååã«ãããŸããã -
BufferSizeããããªã㯠API ã§å ¬éãããŠããå Žåãåãªãintã§ã¯ãªãæå³ã«èª€ã£ãŠè§£éãããå¯èœæ§ããããŸãã éåžžããã¡ã€ã³åã«ã¯è€æ°ã®å±æ§ããããintã®ãããªããªããã£ãåã§ã¯ãããŸããã ãã®ç¥ç§°ã¯ããã®ãããªåæã«éåããŸãã -
BufferSize(ãã¹ã«ã«ã±ãŒã¹) ã瀺ãã®ã¯ããã®åãããå€ãã®ããŒã¿ãä¿æããŠããããšã§ãã - 颿°ã«ååä»ãåŒæ°ãæå®ããå Žåãšæ¯ã¹ãŠããã®å¥åã§ã¯ãããããããåäžããŠããŸããã
- ç¥ç§°ã¯ã³ã³ãã€ã«ããã IL ã«çŸããŸãããããã¯åãªãæŽæ°ã§ããããã®å¥åã¯ã³ã³ãã€ã«æã«ã®ã¿ååšããæ§æèŠçŽ ã§ãã
module Networking =
...
let send data (bufferSize: int) = ...
èŠçŽãããšãåç¥ç§°ã®èœãšã穎ã¯ãããããçç¥ããŠããåã®æœè±¡åã§ã¯ãªããšããããšã§ãã åã®äŸã§ã¯ãBufferSize ã¯ã衚é¢äžã¯ int ãšåæ§ã§ãå
éšã«ã¯äœåãªããŒã¿ããªããåã·ã¹ãã ã®å©ç¹ã int ã«æ¢ã«ãããã®ä»¥äžã®ãã®ã¯ãããŸããã
åã®ç¥ç§°ã䜿çšããŠãã¡ã€ã³ã衚ãå¥ã®æ¹æ³ãšããŠã¯ãåäžã±ãŒã¹ã®å€å¥å ±çšäœã䜿çšããããšããããŸãã åã®ãµã³ãã«ã¯æ¬¡ã®ããã«ã¢ãã«åã§ããŸãã
type BufferSize = BufferSize of int
BufferSize ãšãã®åºã«ãªãå€ã®èгç¹ã§åäœããã³ãŒããèšè¿°ããå Žåã¯ãä»»æã®æŽæ°ãæž¡ãã®ã§ã¯ãªããåãæ§ç¯ããå¿
èŠããããŸãã
module Networking =
...
let send data (BufferSize size) =
...
ããã«ããã颿°ã®åŒã³åºãåã«å€ãã©ããããããã«åŒã³åºãå
ã send åãæ§ç¯ããå¿
èŠããããããä»»æã®æŽæ°ã誀ã£ãŠ BufferSize 颿°ã«æž¡ãå¯èœæ§ãäœããªããŸãã