Note
ãã®ããŒãžã«ã¢ã¯ã»ã¹ããã«ã¯ãæ¿èªãå¿ èŠã§ãã ãµã€ã³ã€ã³ãŸãã¯ãã£ã¬ã¯ããªã®å€æŽã詊ãããšãã§ããŸãã
ãã®ããŒãžã«ã¢ã¯ã»ã¹ããã«ã¯ãæ¿èªãå¿ èŠã§ãã ãã£ã¬ã¯ããªã®å€æŽã詊ãããšãã§ããŸãã
ãã®èšäºã§ã¯ãF# ã³ãŒãã§æ¬¡ã®ããšãå®çŸããããã«ã³ãŒãããã©ãŒãããããæ¹æ³ã®ã¬ã€ãã©ã€ã³ã瀺ããŸãã
- ããèªã¿ããããã
- Visual Studio Code ããã®ä»ã®ãšãã£ã¿ãŒã®ãã©ãŒããã ããŒã«ã«ãã£ãŠé©çšãããèŠåã«æºæ ãã
- ãªã³ã©ã€ã³ã®ä»ã®ã³ãŒããšåæ§ã§ãã
ã³ãŒãã£ã³ã°èŠåãšã³ã³ããŒãã³ã ãã¶ã€ã³ã®ã¬ã€ãã©ã€ã³ã«é¢ããèšäºãåç §ããŠãã ããããããã®èšäºã§ãååä»ãèŠåã«ã€ããŠèª¬æããŠããŸãã
ã³ãŒãã®èªåæžåŒèšå®
Fantomas ã³ãŒã ãã©ãŒããã¿ã¯ãã³ãŒãã®èªåãã©ãŒãããã®ããã® F# ã³ãã¥ããã£ã®æšæºããŒã«ã§ãã æ¢å®ã®èšå®ã¯ããã®ã¹ã¿ã€ã« ã¬ã€ãã«å¯Ÿå¿ããŠããŸãã
ãã®ã³ãŒã ãã©ãŒããã¿ã䜿çšããããšã匷ããå§ãããŸãã F# ããŒã å ã§ã¯ãã³ãŒã ãã©ãŒãããã®ä»æ§ã«åæããããŒã ãªããžããªã«ãã§ãã¯ã€ã³ãããã³ãŒã ãã©ãŒããã¿ã®åææžã¿ã®èšå®ãã¡ã€ã«ã«é¢ããŠä»æ§ãäœç³»åããå¿ èŠããããŸãã
ãã©ãŒãããã«ã€ããŠã®äžè¬çãªèŠå
F# ã§ã¯ãããã©ã«ãã§ç©ºçœã®éèŠæ§ãããã空çœã«ææã«åå¿ããŸãã æ¬¡ã®ã¬ã€ãã©ã€ã³ã¯ãããã«ãã£ãŠèª²ãããå¯èœæ§ã®ããåé¡ã®å¯ŸåŠæ¹æ³ã«é¢ããã¬ã€ãã³ã¹ãæäŸããããšãç®çãšããŠããŸãã
ã¿ãã§ã¯ãªãã¹ããŒã¹ã䜿çšãã
ã€ã³ãã³ããå¿ èŠãªå Žåã¯ãã¿ãã§ã¯ãªããã¹ããŒã¹ã䜿çšããå¿ èŠããããŸãã F# ã³ãŒãã§ã¯ã¿ãã䜿çšããŸãããæååãªãã©ã«ãŸãã¯ã³ã¡ã³ãã®å€éšã§ã¿ãæåãæ€åºããããšãã³ã³ãã€ã©ã«ãã£ãŠãšã©ãŒãçæãããŸãã
æŽåæ§ã®ããã€ã³ãã³ãã䜿çšãã
ã€ã³ãã³ããæå®ããå Žåã¯ãå°ãªããšã 1 ã€ã®ã¹ããŒã¹ãå¿ èŠã§ãã çµç¹ã§ãã€ã³ãã³ãã«äœ¿çšããã¹ããŒã¹ã®æ°ãæå®ããããã®ã³ãŒãã£ã³ã°æšæºãäœæã§ããŸããã€ã³ãã³ããçºçããã¬ãã«ããšã«ã2 ã€ã3 ã€ããŸã㯠4 ã€ã®ã€ã³ãã³ã ã¹ããŒã¹ãäžè¬çã§ãã
ã€ã³ãã³ãã«ã€ã 4 ã€ã®ã¹ããŒã¹ããå§ãããŸãã
ãã ããããã°ã©ã ã®ã€ã³ãã³ãã¯äž»èгçãªåé¡ã§ãã ããªãšãŒã·ã§ã³ã¯åé¡ãããŸããããåŸãå¿ èŠãããæåã®èŠåã¯ãã€ã³ãã³ãã®äžè²«æ§ã§ãã äžè¬çã«åãå ¥ããããŠããã€ã³ãã³ãã®ã¹ã¿ã€ã«ãéžæããã³ãŒãããŒã¹å šäœã§äœç³»çã«äœ¿çšããŸãã
ååã®é·ãã®åœ±é¿ãåãããã©ãŒããããé¿ãã
ååä»ãã®åœ±é¿ãåããã€ã³ãã³ããšã¢ã©ã€ã³ã¡ã³ãã¯é¿ããããã«ããŠãã ããã
// âïž OK
let myLongValueName =
someExpression
|> anotherExpression
// â Not OK
let myLongValueName = someExpression
|> anotherExpression
// âïž OK
let myOtherVeryLongValueName =
match
someVeryLongExpressionWithManyParameters
parameter1
parameter2
parameter3
with
| Some _ -> ()
| ...
// â Not OK
let myOtherVeryLongValueName =
match someVeryLongExpressionWithManyParameters parameter1
parameter2
parameter3 with
| Some _ -> ()
| ...
// â Still Not OK
let myOtherVeryLongValueName =
match someVeryLongExpressionWithManyParameters
parameter1
parameter2
parameter3 with
| Some _ -> ()
| ...
ãããåé¿ããäž»ãªçç±ã¯æ¬¡ã®ãšããã§ãã
- éèŠãªã³ãŒããäžçªå³ã«ç§»åããã
- å®éã®ã³ãŒãã«äœ¿ããå¹ ãæžã£ãŠãã
- ååã倿Žãããšãã¢ã©ã€ã³ã¡ã³ããå£ãããããããã
äœåãªç©ºçœãé¿ãã
ãã®ã¹ã¿ã€ã« ã¬ã€ãã§èª¬æãããŠããå Žåãé€ããF# ã³ãŒãã«äœåãªç©ºçœãå«ããªãã§ãã ããã
// âïž OK
spam (ham 1)
// â Not OK
spam ( ham 1 )
ã³ã¡ã³ãã®ãã©ãŒããã
ããã㯠ã³ã¡ã³ããããè€æ°ã®ããã«ã¹ã©ãã·ã¥ ã³ã¡ã³ããåªå ããŸãã
// Prefer this style of comments when you want
// to express written ideas on multiple lines.
(*
Block comments can be used, but use sparingly.
They are useful when eliding code sections.
*)
ã³ã¡ã³ãã¯ãæåã®æåã倧æåã«ããŠãé©åãªåœ¢åŒã®èªå¥ãŸãã¯æã«ããå¿ èŠããããŸãã
// âïž A good comment.
let f x = x + 1 // Increment by one.
// â two poor comments
let f x = x + 1 // plus one
XML ããã¥ã¡ã³ã ã³ã¡ã³ãã®ãã©ãŒãããã«ã€ããŠã¯ãåŸè¿°ããã宣èšã®ãã©ãŒãããããåç §ããŠãã ããã
åŒã®ãã©ãŒãããå
ãã®ã»ã¯ã·ã§ã³ã§ã¯ãããŸããŸãªçš®é¡ã®åŒã®ãã©ãŒãããã«ã€ããŠèª¬æããŸãã
æåååŒã®ãã©ãŒããã
æååãªãã©ã«ãšè£éãããæååã¯ãè¡ã®é·ãã«é¢ä¿ãªãã1 è¡ã®ãŸãŸã«ããŸãã
let serviceStorageConnection =
$"DefaultEndpointsProtocol=https;AccountName=%s{serviceStorageAccount.Name};AccountKey=%s{serviceStorageAccountKey.Value}"
è£éåŒãè€æ°è¡ã«ããããšã¯ãæšå¥šãããŸããã 代ããã«ãåŒã®çµæãå€ã«ãã€ã³ããããããè£éãããæååã§äœ¿çšããŸãã
ã¿ãã«åŒã®ãã©ãŒããã
ã¿ãã«ã®ã€ã³ã¹ã¿ã³ã¹åã¯ãã£ãã§å²ã¿ããã®äžã®åºåãã³ã³ãã®åŸã«ã¯ 1 ã€ã®ã¹ããŒã¹ã眮ãå¿
èŠããããŸã (äŸ: (1, 2)ã(x, y, z))ã
// âïž OK
let pair = (1, 2)
let triples = [ (1, 2, 3); (11, 12, 13) ]
äžè¬çã«ãã¿ãã«ã®ãã¿ãŒã³ãããã³ã°ã§ã¯æ¬åŒ§ãçç¥ããããšãã§ããŸãã
// âïž OK
let (x, y) = z
let x, y = z
// âïž OK
match x, y with
| 1, _ -> 0
| x, 1 -> 0
| x, y -> 1
ãŸããã¿ãã«ã颿°ã®æ»ãå€ã®å Žåã¯ãäžè¬ã«ãã£ããçç¥ããããšãã§ããŸãã
// âïž OK
let update model msg =
match msg with
| 1 -> model + 1, []
| _ -> model, [ msg ]
èŠçŽãããšãã¿ãã«ã®ã€ã³ã¹ã¿ã³ã¹åã¯ãã£ãã§å²ãã®ã奜ãŸããã§ãããã¿ãã«ããã¿ãŒã³ ãããã³ã°ãæ»ãå€ã«äœ¿ãå Žåã¯ããã£ãããªããŠãåé¡ãªããšèããããŠããŸãã
ã¢ããªã±ãŒã·ã§ã³åŒã®ãã©ãŒããã
颿°ãŸãã¯ã¡ãœããã®é©çšã®ãã©ãŒãããã®éãè¡ã®å¹ ãèš±å¯ãããå Žåã¯ãåãè¡ã«åŒæ°ãæå®ãããŸãã
// âïž OK
someFunction1 x.IngredientName x.Quantity
åŒæ°ã§å¿ èŠãšãããå Žåãé€ãããã£ãã¯çç¥ããŠãã ããã
// âïž OK
someFunction1 x.IngredientName
// â Not preferred - parentheses should be omitted unless required
someFunction1 (x.IngredientName)
// âïž OK - parentheses are required
someFunction1 (convertVolumeToLiter x)
è€æ°ã®ã«ãªãŒååŒæ°ãæå®ããŠåŒã³åºãå Žåã¯ãã¹ããŒã¹ãçç¥ããªãã§ãã ããã
// âïž OK
someFunction1 (convertVolumeToLiter x) (convertVolumeUSPint x)
someFunction2 (convertVolumeToLiter y) y
someFunction3 z (convertVolumeUSPint z)
// â Not preferred - spaces should not be omitted between arguments
someFunction1(convertVolumeToLiter x)(convertVolumeUSPint x)
someFunction2(convertVolumeToLiter y) y
someFunction3 z(convertVolumeUSPint z)
æ¢å®ã®ãã©ãŒãããèŠåã§ã¯ãã¿ãã«åœ¢åŒã®åŒæ°ãŸãã¯ãã£ãã§å²ãŸããåŒæ°ã«å°æåã®é¢æ°ãé©çšããå ŽåãåäžåŒæ°ã䜿çšãããŠããŠããã¹ããŒã¹ã远å ãããŸãã
// âïž OK
someFunction2 ()
// âïž OK
someFunction3 (x.Quantity1 + x.Quantity2)
// â Not OK, formatting tools will add the extra space by default
someFunction2()
// â Not OK, formatting tools will add the extra space by default
someFunction3(x.IngredientName, x.Quantity)
æ¢å®ã®ãã©ãŒãããèŠåã§ã¯ãã¿ãã«åœ¢åŒã®åŒæ°ã«å€§æåã®ã¡ãœãããé©çšããå Žåã«ã¹ããŒã¹ã¯è¿œå ãããŸããã ããã¯ãå€ãã®å Žåãããã Fluent ããã°ã©ãã³ã°ã§äœ¿çšãããããã§ãã
// âïž OK - Methods accepting parenthesize arguments are applied without a space
SomeClass.Invoke()
// âïž OK - Methods accepting tuples are applied without a space
String.Format(x.IngredientName, x.Quantity)
// â Not OK, formatting tools will remove the extra space by default
SomeClass.Invoke ()
// â Not OK, formatting tools will remove the extra space by default
String.Format (x.IngredientName, x.Quantity)
ååã®æåŸã®éšåã¯ãé©çšãããèŠåãæ±ºå®ããŸãã ååã®å é éšã«åã¯åœ±é¿ããŸãã:
// âïž OK - `convertTo` is lower-case, so the space is added
Volume.Conversion.convertTo (x.Quantity, Liter)
// âïž OK - `Contains` is capitalized, so no space is added
recipe.Ingredients.Contains(x.IngredientName)
ã©ã¡ãã®èŠåããé©çšãããå šäœããããã§åºåããããã¬ãŒã³ãªååãã€ãŸããããã§åºåãããèå¥åã§ããããã以å€ã®å Žåã«ã®ã¿é©çšãããŸãã åŒã³åºããã€ã³ããã¯ã¹ãååã§ã¯ãªãã¬ã·ãŒããŒããŸãã¯åã®é©çšãæ¬åŒ§ã®åã«æ¥ãå Žåãã¹ããŒã¹ã¯æ¿å ¥ãããŸããã ããã«ãããFluent ãã§ãŒã³ãåäžã®ã¹ããŒã¹åŒã³åºãã§çµãã£ãŠããŸãããšãé²ããŸã:
// âïž OK - a plain dotted name, however many dots it has
recipe.Ingredients.convertTo (Liter)
// âïž OK - a call comes before the parentheses, so no space is added
getRecipe().convertTo(Liter)
// âïž OK - an index comes before the parentheses
recipe.Ingredients[0].convertTo(Liter)
// âïž OK - a receiver that isn't a name, such as an expression or a literal
(getRecipe x.IngredientName).convertTo(Liter)
// âïž OK - a type application, on the call itself or with no dots at all
recipe.convertTo<Liter>(x.Quantity)
unbox<Volume>(x.Quantity)
// â Not OK, formatting tools will remove the extra space by default
getRecipe().convertTo (Liter)
recipe.Ingredients[0].convertTo (Liter)
unbox<Volume> (x.Quantity)
åé©çšã®ã±ãŒã¹ã¯ãæ¬åŒ§ããã§ã«æžãããŠããå Žåã«ã®ã¿åé¡ã«ãªããŸãã æžåŒèšå®ããŒã«ã§ã¯ãã£ãã远å ãããªãããããã£ããªãã§èšè¿°ãããæ±çšã¢ããªã±ãŒã·ã§ã³ã¯ãã®ãŸãŸæ®ãããŸãã
// âïž OK
unbox<Volume> x.Quantity
ãããã®åãæžåŒèšå®èŠåããã¿ãŒã³ ãããã³ã°ã«é©çšãããŸãã F# ã¹ã¿ã€ã«ã®å€ãäžè²«ããæžåŒã§èšå®ããæ¹æ³:
// âïž OK - Consistent formatting for expressions and patterns
let result = Some(value)
match result with
| Some(x) -> x
| None -> 0
èªã¿ãããã®åé¡ããåŒæ°ãªã¹ããåŒæ°åãé·ããããšããçç±ã§ã颿°ãžã®åŒæ°ãæ¹è¡ããŠæž¡ãå¿ èŠãããå ŽåããããŸãã ãã®ãããªå Žåã¯ã1 ã¬ãã« ã€ã³ãã³ãããŸãã
// âïž OK
someFunction2
x.IngredientName x.Quantity
// âïž OK
someFunction3
x.IngredientName1 x.Quantity2
x.IngredientName2 x.Quantity2
// âïž OK
someFunction4
x.IngredientName1
x.Quantity2
x.IngredientName2
x.Quantity2
// âïž OK
someFunction5
(convertVolumeToLiter x)
(convertVolumeUSPint x)
(convertVolumeImperialPint x)
颿°ã 1 ã€ã®è€æ°è¡ã®ã¿ãã«åœ¢åŒã®åŒæ°ãåãåãå Žåã¯ãååŒæ°ãæ°ããè¡ã«é 眮ããŸãã
// âïž OK
someTupledFunction (
478815516,
"A very long string making all of this multi-line",
1515,
false
)
// OK, but formatting tools will reformat to the above
someTupledFunction
(478815516,
"A very long string making all of this multi-line",
1515,
false)
åŒæ°åŒãçãå Žåã¯ãåŒæ°ãã¹ããŒã¹ã§åºåãã1 è¡ã«åããŸãã
// âïž OK
let person = new Person(a1, a2)
// âïž OK
let myRegexMatch = Regex.Match(input, regex)
// âïž OK
let untypedRes = checker.ParseFile(file, source, opts)
åŒæ°åŒãé·ãå Žåã¯ãå·Šãã£ãã«ã€ã³ãã³ãããã®ã§ã¯ãªããæ¹è¡ã䜿çšã㊠1 ã¬ãã« ã€ã³ãã³ãããŸãã
// âïž OK
let person =
new Person(
argument1,
argument2
)
// âïž OK
let myRegexMatch =
Regex.Match(
"my longer input string with some interesting content in it",
"myRegexPattern"
)
// âïž OK
let untypedRes =
checker.ParseFile(
fileName,
sourceText,
parsingOptionsWithDefines
)
// â Not OK, formatting tools will reformat to the above
let person =
new Person(argument1,
argument2)
// â Not OK, formatting tools will reformat to the above
let untypedRes =
checker.ParseFile(fileName,
sourceText,
parsingOptionsWithDefines)
è€æ°è¡ã®åŒæ° (è€æ°è¡ã®æååãå«ã) ã 1 ã€ãããªãå Žåã§ããåãã«ãŒã«ã該åœããŸãã
// âïž OK
let poemBuilder = StringBuilder()
poemBuilder.AppendLine(
"""
The last train is nearly due
The Underground is closing soon
And in the dark, deserted station
Restless in anticipation
A man waits in the shadows
"""
)
Option.traverse(
create
>> Result.setError [ invalidHeader "Content-Checksum" ]
)
ãã€ãã©ã€ã³åŒè¡šçŸã®ãã©ãŒããã
è€æ°ã®è¡ã䜿çšããå Žåããã€ãã©ã€ã³ |> æŒç®åã¯ãæäœå¯Ÿè±¡ã®åŒã®äžã«é
眮ããå¿
èŠããããŸãã
// âïž OK
let methods2 =
System.AppDomain.CurrentDomain.GetAssemblies()
|> List.ofArray
|> List.map (fun assm -> assm.GetTypes())
|> Array.concat
|> List.ofArray
|> List.map (fun t -> t.GetMethods())
|> Array.concat
// â Not OK, add a line break after "=" and put multi-line pipelines on multiple lines.
let methods2 = System.AppDomain.CurrentDomain.GetAssemblies()
|> List.ofArray
|> List.map (fun assm -> assm.GetTypes())
|> Array.concat
|> List.ofArray
|> List.map (fun t -> t.GetMethods())
|> Array.concat
// â Not OK either
let methods2 = System.AppDomain.CurrentDomain.GetAssemblies()
|> List.ofArray
|> List.map (fun assm -> assm.GetTypes())
|> Array.concat
|> List.ofArray
|> List.map (fun t -> t.GetMethods())
|> Array.concat
éãã€ãã©ã€ã³ <| æŒç®åã®å Žåã¯ãçãåŒã 1 è¡ã«ä¿æããŸãã è¡ã®é·ãã«ãã£ãŠæ¹è¡ãå¿
èŠã«ãªãå Žåã¯ãåŒæ°ãæ°ããè¡ã«é
眮ããäžè²«ããŠé
眮ããŠãã ãã:
// âïž OK - short expressions stay on one line
let result = someFunction <| arg1 <| arg2 <| arg3
// âïž OK - longer expressions can wrap when necessary
failwith
<| sprintf "A very long error message that exceeds reasonable line length: %s - additional details: %s"
longVariableName
anotherLongVariableName
// âïž OK - align continuation lines with the operator
let longResult =
someVeryLongFunctionName
<| firstVeryLongArgumentName
<| secondVeryLongArgumentName
<| thirdVeryLongArgumentName
// â Not OK - unnecessary wrapping of short expressions
failwith <| sprintf "short: %s"
value
ã©ã ãåŒã®ãã©ãŒããã
ã©ã ãåŒãè€æ°è¡ã®åŒã®åŒæ°ãšããŠäœ¿çšãããä»ã®åŒæ°ãç¶ãå Žåã¯ãã©ã ãåŒã®æ¬äœãæ°ããè¡ã«é 眮ãã1 ã¬ãã«ã§ã€ã³ãã³ãããŸãã
// âïž OK
let printListWithOffset a list1 =
List.iter
(fun elem ->
printfn $"A very long line to format the value: %d{a + elem}")
list1
ã©ã ãã®åŒæ°ã颿°ã¢ããªã±ãŒã·ã§ã³ã®æåŸã®åŒæ°ã®å Žåãåãè¡ã®ç¢å°ãŸã§ãã¹ãŠã®åŒæ°ãé 眮ããŸãã
// âïž OK
Target.create "Build" (fun ctx ->
// code
// here
())
// âïž OK
let printListWithOffsetPiped a list1 =
list1
|> List.map (fun x -> x + 1)
|> List.iter (fun elem ->
printfn $"A very long line to format the value: %d{a + elem}")
ãããã©ã ããåæ§ã®æ¹æ³ã§åŠçããŸãã
// âïž OK
functionName arg1 arg2 arg3 (function
| Choice1of2 x -> 1
| Choice2of2 y -> 2)
ã©ã ãã®åã«å è¡ããåŒæ°ãè€æ°è¡ã®åŒæ°ã倿°ããå Žåã¯ã1 ã¬ãã«ã§ãã¹ãŠã®åŒæ°ãã€ã³ãã³ãããŸãã
// âïž OK
functionName
arg1
arg2
arg3
(fun arg4 ->
bodyExpr)
// âïž OK
functionName
arg1
arg2
arg3
(function
| Choice1of2 x -> 1
| Choice2of2 y -> 2)
ã©ã ãåŒã®æ¬äœãè€æ°è¡ã®é·ãã§ããå Žåã¯ãããŒã«ã«ã«ã¹ã³ãŒãèšå®ããã颿°ã«ãªãã¡ã¯ã¿ãªã³ã°ããããšãæ€èšããŠãã ããã
ãã€ãã©ã€ã³ã«ã©ã ãåŒãå«ãŸããŠããå Žåãåã©ã ãåŒã¯éåžžããã€ãã©ã€ã³ã®åã¹ããŒãžã®æåŸã®åŒæ°ã§ãã
// âïž OK, with 4 spaces indentation
let printListWithOffsetPiped list1 =
list1
|> List.map (fun elem -> elem + 1)
|> List.iter (fun elem ->
// one indent starting from the pipe
printfn $"A very long line to format the value: %d{elem}")
// âïž OK, with 2 spaces indentation
let printListWithOffsetPiped list1 =
list1
|> List.map (fun elem -> elem + 1)
|> List.iter (fun elem ->
// one indent starting from the pipe
printfn $"A very long line to format the value: %d{elem}")
ã©ã ãã®åŒæ°ã 1 è¡ã«åãŸããªãå Žåããããã¯ããèªäœãè€æ°è¡ã®å Žåãæ¬¡ã®è¡ã«é 眮ãã1 ã¬ãã«ããšã«ã€ã³ãã³ãããŠãã ããã
// âïž OK
fun
(aVeryLongParameterName: AnEquallyLongTypeName)
(anotherVeryLongParameterName: AnotherLongTypeName)
(yetAnotherLongParameterName: LongTypeNameAsWell)
(youGetTheIdeaByNow: WithLongTypeNameIncluded) ->
// code starts here
()
// â Not OK, code formatters will reformat to the above to respect the maximum line length.
fun (aVeryLongParameterName: AnEquallyLongTypeName) (anotherVeryLongParameterName: AnotherLongTypeName) (yetAnotherLongParameterName: LongTypeNameAsWell) (youGetTheIdeaByNow: WithLongTypeNameIncluded) ->
()
// âïž OK
let useAddEntry () =
fun
(input:
{| name: string
amount: Amount
isIncome: bool
created: string |}) ->
// foo
bar ()
// â Not OK, code formatters will reformat to the above to avoid reliance on whitespace alignment that is contingent to length of an identifier.
let useAddEntry () =
fun (input: {| name: string
amount: Amount
isIncome: bool
created: string |}) ->
// foo
bar ()
lazy åŒã®æžåŒèšå®
1 è¡ã®é å»¶åŒãæžãéã¯ããã¹ãŠã 1 è¡ã«ä¿æããŸãã
// âïž OK
let x = lazy (computeValue())
// âïž OK
let y = lazy (a + b)
è€æ°è¡ã«ãããé
å»¶åŒã®å Žåãéæ¬åŒ§ã lazy ããŒã¯ãŒããšåãè¡ã«é
眮ããåŒã®æ¬äœã 1 段éã€ã³ãã³ãããéãæ¬åŒ§ãéæ¬åŒ§ãšæããŸãã
// âïž OK
let v =
lazy (
// some code
let x = computeExpensiveValue()
let y = computeAnotherValue()
x + y
)
// âïž OK
let handler =
lazy (
let connection = openConnection()
let data = fetchData connection
processData data
)
ããã¯ãè€æ°è¡åŒæ°ãæã€ä»ã®é¢æ°ã¢ããªã±ãŒã·ã§ã³ãšåããã¿ãŒã³ã«åŸããŸãã éå§ãã£ã㯠lazyã®ãŸãŸã§ãåŒã¯ 1 ã¬ãã«ã€ã³ãã³ããããŸãã
ç®è¡åŒããã³ãã€ããªåŒã®ãã©ãŒããã
ãã€ããªç®è¡åŒã®ååŸã«ã¯åžžã«ç©ºçœã䜿çšããŸãã
// âïž OK
let subtractThenAdd x = x - 1 + 3
2 é
- æŒç®åãå²ãŸãªããšãç¹å®ã®æžåŒèšå®ã®éžæè¢ãšçµã¿åãããããå Žåã«ãåé
- ãšããŠè§£éãããå¯èœæ§ããããŸãã
åé
- æŒç®åã§ã¯ãè² æ°åããå€ãåžžã«çŽåŸã«ç¶ããå¿
èŠããããŸãã
// âïž OK
let negate x = -x
// â Not OK
let negateBad x = - x
- æŒç®åã®åŸã«ç©ºçœæåã远å ãããšããã®ä»ã®æŒç®åã§æ··ä¹±ãæãå¯èœæ§ããããŸãã
ãã€ããªæŒç®åã¯ã¹ããŒã¹ã§åºåããŸãã äžçœ®è¡šèšã¯ãåãåã§äžŠã¹ãããšãã§ããŸãã
// âïž OK
let function1 () =
acc +
(someFunction
x.IngredientName x.Quantity)
// âïž OK
let function1 arg1 arg2 arg3 arg4 =
arg1 + arg2 +
arg3 + arg4
ãã®èŠåã¯ãåããã³å®æ°æ³šéã®æž¬å®åäœã«ãé©çšãããŸãã
// âïž OK
type Test =
{ WorkHoursPerWeek: uint<hr / (staff weeks)> }
static member create = { WorkHoursPerWeek = 40u<hr / (staff weeks)> }
// â Not OK
type Test =
{ WorkHoursPerWeek: uint<hr/(staff weeks)> }
static member create = { WorkHoursPerWeek = 40u<hr/(staff weeks)> }
æ¬¡ã®æŒç®åã¯ãF# æšæºã©ã€ãã©ãªã§å®çŸ©ãããŠãããåçã®ãã®ãå®çŸ©ãã代ããã«äœ¿çšããå¿ èŠããããŸãã ãããã®æŒç®åã䜿çšãããšãã³ãŒããèªã¿ãããæ £çšçã«ãªãåŸåãããããã䜿çšããããšããå§ãããŸãã æ¬¡ã®äžèЧã¯ãæšå¥šããã F# æŒç®åããŸãšãããã®ã§ãã
// âïž OK
x |> f // Forward pipeline
f <| x // Reverse pipeline
f >> g // Forward composition
x |> ignore // Discard away a value
x + y // Overloaded addition (including string concatenation)
x - y // Overloaded subtraction
x * y // Overloaded multiplication
x / y // Overloaded division
x % y // Overloaded modulus
x && y // Lazy/short-cut "and"
x || y // Lazy/short-cut "or"
x <<< y // Bitwise left shift
x >>> y // Bitwise right shift
x ||| y // Bitwise or, also for working with âflagsâ enumeration
x &&& y // Bitwise and, also for working with âflagsâ enumeration
x ^^^ y // Bitwise xor, also for working with âflagsâ enumeration
ç¯å²æŒç®ååŒã®ãã©ãŒããã
åŒãã¢ãããã¯ã§ãªãå Žåã«ã®ã¿ã .. ã®åšå²ã«ã¹ããŒã¹ã远å ããŸãã
æŽæ°ãš 1 åèªã®èå¥åã¯ã¢ãããã¯ãšèŠãªãããŸãã
// âïž OK
let a = [ 2..7 ] // integers
let b = [ one..two ] // identifiers
let c = [ ..9 ] // also when there is only one expression
let d = [ 0.7 .. 9.2 ] // doubles
let e = [ 2L .. number / 2L ] // complex expression
let f = [| A.B .. C.D |] // identifiers with dots
let g = [ .. (39 - 3) ] // complex expression
let h = [| 1 .. MyModule.SomeConst |] // not all expressions are atomic
for x in 1..2 do
printfn " x = %d" x
let s = seq { 0..10..100 }
// â Not OK
let a = [ 2 .. 7 ]
let b = [ one .. two ]
ãããã®èŠåã¯ãã¹ã©ã€ã¹ã«ãé©çšãããŸãã
// âïž OK
arr[0..10]
list[..^1]
If åŒã®ãã©ãŒããã
æ¡ä»¶ã®ã€ã³ãã³ãã¯ãããããæ§æããåŒã®ãµã€ãºãšè€éãã«ãã£ãŠç°ãªããŸãã æ¬¡ã®å Žå㯠1 è¡ã«èšè¿°ããŸãã
-
condãe1ãe2ãçãã -
e1ãše2èªäœãif/then/elseåŒã§ã¯ãªãã
// âïž OK
if cond then e1 else e2
else åŒããªãå Žåã¯ãåŒå šäœã 1 è¡ã«èšè¿°ããªãããšããå§ãããŸãã ããã¯ãåœä»€åã³ãŒãã颿°åãšåºå¥ããããã§ãã
// âïž OK
if a then
()
// â Not OK, code formatters will reformat to the above by default
if a then ()
ããããã®åŒãè€æ°è¡ã®å Žåã¯ã忡件åå²ãè€æ°è¡ã«ããå¿ èŠããããŸãã
// âïž OK
if cond then
let e1 = something()
e1
else
e2
// â Not OK
if cond then
let e1 = something()
e1
else e2
elif ãš else ãå«ãè€æ°ã®æ¡ä»¶ã¯ã1 è¡ã® if åŒã®ã«ãŒã«ã«åŸããšãã® if/then/else ãšåãã¹ã³ãŒãã§ã€ã³ãã³ããããŸãã
// âïž OK
if cond1 then e1
elif cond2 then e2
elif cond3 then e3
else e4
æ¡ä»¶ãŸãã¯åŒã®ãããããè€æ°è¡ã®å Žåãif/then/else åŒå
šäœãè€æ°è¡ã«ãªããŸãã
// âïž OK
if cond1 then
let e1 = something()
e1
elif cond2 then
e2
elif cond3 then
e3
else
e4
// â Not OK
if cond1 then
let e1 = something()
e1
elif cond2 then e2
elif cond3 then e3
else e4
æ¡ä»¶ãè€æ°è¡ã§ããããåäžè¡ã®æ¢å®ã®èš±å®¹ç¯å²ãè¶
ããŠããå Žåãæ¡ä»¶åŒã§ã¯ 1 ã€ã®ã€ã³ãã³ããšæ°ããè¡ã䜿çšããå¿
èŠããããŸãã
é·ãæ¡ä»¶åŒãã«ãã»ã«åãããšãã¯ãif ããŒã¯ãŒããš then ããŒã¯ãŒããæããå¿
èŠããããŸãã
// âïž OK, but better to refactor, see below
if
complexExpression a b && env.IsDevelopment()
|| someFunctionToCall
aVeryLongParameterNameOne
aVeryLongParameterNameTwo
aVeryLongParameterNameThree
then
e1
else
e2
// âïžThe same applies to nested `elif` or `else if` expressions
if a then
b
elif
someLongFunctionCall
argumentOne
argumentTwo
argumentThree
argumentFour
then
c
else if
someOtherLongFunctionCall
argumentOne
argumentTwo
argumentThree
argumentFour
then
d
ãã ããé©åãªåœ¢åŒã¯ãé·ãæ¡ä»¶ã let ãã€ã³ãã£ã³ã°ãŸãã¯å¥ã®é¢æ°ã«ãªãã¡ã¯ã¿ãªã³ã°ããããšã§ãã
// âïž OK
let performAction =
complexExpression a b && env.IsDevelopment()
|| someFunctionToCall
aVeryLongParameterNameOne
aVeryLongParameterNameTwo
aVeryLongParameterNameThree
if performAction then
e1
else
e2
å ±çšäœã±ãŒã¹åŒã®ãã©ãŒããã
å€å¥å ±çšäœã±ãŒã¹ã®é©çšã¯ã颿°ããã³ã¡ãœããã®é©çšãšåãèŠåã«åŸããŸãã ã€ãŸããååã倧æåã«ãªã£ãŠãããããã³ãŒã ãã©ãŒããã¿ã¯ã¿ãã«ã®åã«ããã¹ããŒã¹ãåé€ããŸãã
// âïž OK
let opt = Some("A", 1)
// OK, but code formatters will remove the space
let opt = Some ("A", 1)
颿°ã®é©çšãšåæ§ã«ãè€æ°è¡ã«ããã£ãŠåå²ãããã³ã³ã¹ãã©ã¯ã·ã§ã³ã§ã¯ã€ã³ãã³ãã䜿çšããå¿ èŠããããŸãã
// âïž OK
let tree1 =
BinaryNode(
BinaryNode (BinaryValue 1, BinaryValue 2),
BinaryNode (BinaryValue 3, BinaryValue 4)
)
ãªã¹ãåŒãšé ååŒã®ãã©ãŒããã
x :: l æŒç®åã®ååŸã«ã¹ããŒã¹ã䜿çšã㊠:: ãèšè¿°ããŸã (:: ã¯æ¿å
¥æŒç®åã§ãããããã¹ããŒã¹ã§å²ã¿ãŸã)ã
1 ã€ã®è¡ã§å®£èšããããªã¹ããšé åã§ã¯ãå·Šè§ãã£ãã®åŸãšå³è§ãã£ãã®åã«ã¹ããŒã¹ãå¿ èŠã§ãã
// âïž OK
let xs = [ 1; 2; 3 ]
// âïž OK
let ys = [| 1; 2; 3; |]
2 ã€ã®ç°ãªãæ¬åŒ§æŒç®åã®éã«ã¯ãåžžã«å°ãªããšã 1 ã€ã®ç©ºçœã䜿çšããŸãã ããšãã°ã[ ãš { ãšã®éã«ã¯ã¹ããŒã¹ã眮ããŸãã
// âïž OK
[ { Ingredient = "Green beans"; Quantity = 250 }
{ Ingredient = "Pine nuts"; Quantity = 250 }
{ Ingredient = "Feta cheese"; Quantity = 250 }
{ Ingredient = "Olive oil"; Quantity = 10 }
{ Ingredient = "Lemon"; Quantity = 1 } ]
// â Not OK
[{ Ingredient = "Green beans"; Quantity = 250 }
{ Ingredient = "Pine nuts"; Quantity = 250 }
{ Ingredient = "Feta cheese"; Quantity = 250 }
{ Ingredient = "Olive oil"; Quantity = 10 }
{ Ingredient = "Lemon"; Quantity = 1 }]
ã¿ãã«ã®ãªã¹ããŸãã¯é åã«ãåãã¬ã€ãã©ã€ã³ã該åœããŸãã
è€æ°ã®è¡ã«ããã£ãŠåå²ããããªã¹ããšé åã¯ãã¬ã³ãŒããšåæ§ã®ã«ãŒã«ã«åŸããŸãã
// âïž OK
let pascalsTriangle =
[| [| 1 |]
[| 1; 1 |]
[| 1; 2; 1 |]
[| 1; 3; 3; 1 |]
[| 1; 4; 6; 4; 1 |]
[| 1; 5; 10; 10; 5; 1 |]
[| 1; 6; 15; 20; 15; 6; 1 |]
[| 1; 7; 21; 35; 35; 21; 7; 1 |]
[| 1; 8; 28; 56; 70; 56; 28; 8; 1 |] |]
ã¬ã³ãŒãã®å Žåãšåæ§ã«ãå·Šããã³å³è§ãã£ããç¬èªã®è¡ã§å®£èšãããšãã³ãŒãã®ç§»åã颿°ãžã®ãã€ãã容æã«ãªããŸãã
// âïž OK
let pascalsTriangle =
[|
[| 1 |]
[| 1; 1 |]
[| 1; 2; 1 |]
[| 1; 3; 3; 1 |]
[| 1; 4; 6; 4; 1 |]
[| 1; 5; 10; 10; 5; 1 |]
[| 1; 6; 15; 20; 15; 6; 1 |]
[| 1; 7; 21; 35; 35; 21; 7; 1 |]
[| 1; 8; 28; 56; 70; 56; 28; 8; 1 |]
|]
ãªã¹ããŸãã¯é
ååŒããã€ã³ãã®å³åŽã«ããå Žåã¯ãStroustrup ã¹ã¿ã€ã«ã䜿çšããããšããå§ãããŸãã
// âïž OK
let pascalsTriangle = [|
[| 1 |]
[| 1; 1 |]
[| 1; 2; 1 |]
[| 1; 3; 3; 1 |]
[| 1; 4; 6; 4; 1 |]
[| 1; 5; 10; 10; 5; 1 |]
[| 1; 6; 15; 20; 15; 6; 1 |]
[| 1; 7; 21; 35; 35; 21; 7; 1 |]
[| 1; 8; 28; 56; 70; 56; 28; 8; 1 |]
|]
ãã ãããªã¹ããŸãã¯é ååŒããã€ã³ãã®å³èŸºã«ãªãå ŽåïŒå¥ã®ãªã¹ããé åå ã«ããå Žåãªã©ïŒããã®å éšåŒãè€æ°ã®è¡ã«ãŸãããå¿ èŠããããšãã¯ãåæ¬åŒ§ãç¬èªã®è¡ã«é 眮ããå¿ èŠããããŸãã
// âïž OK - The outer list follows `Stroustrup` style, while the inner lists place their brackets on separate lines
let fn a b = [
[
someReallyLongValueThatWouldForceThisListToSpanMultipleLines
a
]
[
b
someReallyLongValueThatWouldForceThisListToSpanMultipleLines
]
]
// â Not okay
let fn a b = [ [
someReallyLongValueThatWouldForceThisListToSpanMultipleLines
a
]; [
b
someReallyLongValueThatWouldForceThisListToSpanMultipleLines
] ]
é åããŸãã¯ãªã¹ãå ã®ã¬ã³ãŒãåã«ãåãèŠåãé©çšãããŸãã
// âïž OK - The outer list follows `Stroustrup` style, while the inner lists place their brackets on separate lines
let fn a b = [
{
Foo = someReallyLongValueThatWouldForceThisListToSpanMultipleLines
Bar = a
}
{
Foo = b
Bar = someReallyLongValueThatWouldForceThisListToSpanMultipleLines
}
]
// â Not okay
let fn a b = [ {
Foo = someReallyLongValueThatWouldForceThisListToSpanMultipleLines
Bar = a
}; {
Foo = b
Bar = someReallyLongValueThatWouldForceThisListToSpanMultipleLines
} ]
ããã°ã©ã ã«ãã£ãŠé
åãšãªã¹ããçæããå Žåã¯ãå€ãåžžã«çæããããšã㯠-> ã do ... yield ããåªå
ã§ãã
// âïž OK
let squares = [ for x in 1..10 -> x * x ]
// â Not preferred, use "->" when a value is always generated
let squares' = [ for x in 1..10 do yield x * x ]
以åã®ããŒãžã§ã³ã® F# ã§ã¯ãããŒã¿ãæ¡ä»¶ä»ãã§çæãããå Žåããé£ç¶ããåŒãè©äŸ¡ãããå Žåã«ãyield ãæå®ããå¿
èŠããããŸããã 以åã® F# èšèªããŒãžã§ã³ã§ã³ã³ãã€ã«ããå¿
èŠãããå Žåãé€ãããããã® yield ããŒã¯ãŒããçãããšããå§ãããŸãã
// âïž OK
let daysOfWeek includeWeekend =
[
"Monday"
"Tuesday"
"Wednesday"
"Thursday"
"Friday"
if includeWeekend then
"Saturday"
"Sunday"
]
// â Not preferred - omit yield instead
let daysOfWeek' includeWeekend =
[
yield "Monday"
yield "Tuesday"
yield "Wednesday"
yield "Thursday"
yield "Friday"
if includeWeekend then
yield "Saturday"
yield "Sunday"
]
å Žåã«ãã£ãŠã¯ãdo...yield ã«ãã£ãŠèªã¿ããããªãããšããããŸãã ãã®ãããªã±ãŒã¹ã¯ã䞻芳çã§ã¯ãããŸãããèæ
®ããå¿
èŠããããŸãã
ã¬ã³ãŒã衚çŸã®ãã©ãŒããã
çãã¬ã³ãŒãã¯ã1 è¡ã«èšè¿°ã§ããŸãã
// âïž OK
let point = { X = 1.0; Y = 0.0 }
ããé·ãã¬ã³ãŒãã¯ãã©ãã«ã«æ°ããè¡ã䜿çšããå¿ èŠããããŸãã
// âïž OK
let rainbow =
{ Boss = "Jeffrey"
Lackeys = ["Zippy"; "George"; "Bungle"] }
è€æ°è¡ãã£ãã®ãã©ãŒããã ã¹ã¿ã€ã«
è€æ°ã®è¡ã«ãŸãããã¬ã³ãŒãã®å Žåãäžè¬çã«äœ¿çšããããã©ãŒããã ã¹ã¿ã€ã«ã¯ãCrampedãAlignedãStroustrup ã® 3 ã€ã§ãã
Cramped ã¹ã¿ã€ã«ã¯ãã³ã³ãã€ã©ãã³ãŒããç°¡åã«è§£æã§ããã¹ã¿ã€ã«ãåªå
ãããåŸåããããããF# ã³ãŒãã®æ¢å®ã®ã¹ã¿ã€ã«ã§ãã
Aligned ã¹ã¿ã€ã«ãš Stroustrup ã¹ã¿ã€ã«ã®äž¡æ¹ã䜿çšãããšãã¡ã³ããŒã®äžŠã¹æ¿ãã容æã«ãªãããªãã¡ã¯ã¿ãªã³ã°ã容æã«ãªãå¯èœæ§ãããã³ãŒããçæãããç¹å®ã®ç¶æ³ã§ã¯ãã詳现ãªã³ãŒããå¿
èŠã«ãªãå Žåããããšããæ¬ ç¹ããããŸãã
Cramped: å±¥æŽã®æšæºã§ãããæ¢å®ã® F# ã¬ã³ãŒã圢åŒã éãæ¬åŒ§ã¯æåã®ã¡ã³ããŒãšåãè¡ã«çœ®ãããéããæ¬åŒ§ã¯æåŸã®ã¡ã³ããŒãšåãè¡ã«çœ®ãããŸããlet rainbow = { Boss1 = "Jeffrey" Boss2 = "Jeffrey" Boss3 = "Jeffrey" Lackeys = [ "Zippy"; "George"; "Bungle" ] }Aligned: ãã£ãã¯ããããåºæã®è¡ã«èšè¿°ããåãåã«é 眮ããŸããlet rainbow = { Boss1 = "Jeffrey" Boss2 = "Jeffrey" Boss3 = "Jeffrey" Lackeys = ["Zippy"; "George"; "Bungle"] }Stroustrup: éãæ¬åŒ§ã¯ãã€ã³ãã£ã³ã°ãšåãè¡ã«çœ®ããéãæ¬åŒ§ã¯ããèªäœã®è¡ã«é 眮ããŸããlet rainbow = { Boss1 = "Jeffrey" Boss2 = "Jeffrey" Boss3 = "Jeffrey" Lackeys = [ "Zippy"; "George"; "Bungle" ] }
ãªã¹ãããã³é åèŠçŽ ã«ã¯ãåããã©ãŒããã ã¹ã¿ã€ã« ã«ãŒã«ãé©çšãããŸãã
ã³ããŒãšæŽæ°ã®ã¬ã³ãŒãåŒã®ãã©ãŒããã
ã³ããŒãšæŽæ°ã®ã¬ã³ãŒãåŒãã¬ã³ãŒãã§ãããããåæ§ã®ã¬ã€ãã©ã€ã³ã該åœããŸãã
çãåŒã¯ã1 è¡ã«åããããšãã§ããŸãã
// âïž OK
let point2 = { point with X = 1; Y = 2 }
ããé·ãåŒã§ã¯ãæ°ããè¡ã䜿çšããäžèšã®ååä»ãèŠåã®ããããã«åºã¥ããŠãã©ãŒãããããå¿ èŠããããŸãã
// âïž OK - Cramped
let newState =
{ state with
Foo =
Some
{ F1 = 0
F2 = "" } }
// âïž OK - Aligned
let newState =
{
state with
Foo =
Some
{
F1 = 0
F2 = ""
}
}
// âïž OK - Stroustrup
let newState = {
state with
Foo =
Some {
F1 = 0
F2 = ""
}
}
泚: ã³ããŒãšæŽæ°ã®åŒã« Stroustrup ã¹ã¿ã€ã«ã䜿çšããå Žåã¯ãã³ããŒããã¬ã³ãŒãåãããããã«ã¡ã³ããŒãã€ã³ãã³ããã "å¿
èŠããããŸã"ã
// âïž OK
let bilbo = {
hobbit with
Name = "Bilbo"
Age = 111
Region = "The Shire"
}
// â Not OK - Results in compiler error: "Possible incorrect indentation: this token is offside of context started at position"
let bilbo = {
hobbit with
Name = "Bilbo"
Age = 111
Region = "The Shire"
}
ãã¿ãŒã³ ãããã³ã°ã®ãã©ãŒããã
ã€ã³ãã³ãã®ãªãäžèŽã®æ¡é
ããšã« | ã䜿çšããŸãã åŒãçããããããã®éšååŒãåçŽãªãã®ã§ããå Žåã¯ã1 è¡ã䜿çšããããšãæ€èšã§ããŸãã
// âïž OK
match l with
| { him = x; her = "Posh" } :: tail -> x
| _ :: tail -> findDavid tail
| [] -> failwith "Couldn't find David"
// â Not OK, code formatters will reformat to the above by default
match l with
| { him = x; her = "Posh" } :: tail -> x
| _ :: tail -> findDavid tail
| [] -> failwith "Couldn't find David"
ãã¿ãŒã³ ãããã³ã°ã®æžåŒèšå®ã¯ãåŒã®æžåŒèšå®ãšäžèŽããå¿ èŠããããŸãã ãã¿ãŒã³åŒæ°ã®å§ããã£ãã®åã«ã¹ããŒã¹ã远å ããªãã§ãã ããã
// âïž OK
match x with
| Some(y) -> y
| None -> 0
// âïž OK
match data with
| Success(value) -> value
| Error(msg) -> failwith msg
// â Not OK, pattern formatting should match expression formatting
match x with
| Some (y) -> y
| None -> 0
ãã ããåŒã®å Žåãšåæ§ã«ããã¿ãŒã³å ã§ã¯åå¥ã®ã«ãªãŒååŒæ°ã®éã«ã¹ããŒã¹ãå ¥ããŠãã ãã:
// âïž OK - space between curried arguments
match x with
| Pattern arg (a, b) -> processValues arg a b
// â Not OK - missing space between curried arguments
match x with
| Pattern arg(a, b) -> processValues arg a b
ãã¿ãŒã³äžèŽã®ç¢å°ã®å³åŽã«ããåŒã倧ããããå Žåã¯ãmatch/| ãã 1 ã¹ããã ã€ã³ãã³ããããæ¬¡ã®è¡ã«ç§»åããŠãã ããã
// âïž OK
match lam with
| Var v -> 1
| Abs(x, body) ->
1 + sizeLambda body
| App(lam1, lam2) ->
sizeLambda lam1 + sizeLambda lam2
if æ¡ä»¶ã倧ããå Žåãšåæ§ã«ãäžèŽåŒãè€æ°è¡ã§ããããåäžè¡ã®æ¢å®ã®èš±å®¹ç¯å²ãè¶
ããŠããå Žåã¯ãäžèŽåŒã§ 1 ã€ã®ã€ã³ãã³ããšæ°ããè¡ã䜿çšããå¿
èŠããããŸãã
é·ãäžèŽåŒãã«ãã»ã«åãããšãã¯ãmatch ããŒã¯ãŒããš with ããŒã¯ãŒããæããå¿
èŠããããŸãã
// âïž OK, but better to refactor, see below
match
complexExpression a b && env.IsDevelopment()
|| someFunctionToCall
aVeryLongParameterNameOne
aVeryLongParameterNameTwo
aVeryLongParameterNameThree
with
| X y -> y
| _ -> 0
ãã ããé·ãäžèŽåŒã let ãã€ã³ãã£ã³ã°ãŸãã¯å¥ã®é¢æ°ã«ãªãã¡ã¯ã¿ãªã³ã°ããããšã¯ãããé©åãªåœ¢åŒã§ãã
// âïž OK
let performAction =
complexExpression a b && env.IsDevelopment()
|| someFunctionToCall
aVeryLongParameterNameOne
aVeryLongParameterNameTwo
aVeryLongParameterNameThree
match performAction with
| X y -> y
| _ -> 0
ãã¿ãŒã³ãããã®ç¢å°ãæŽåããããšã¯é¿ããŠãã ããã
// âïž OK
match lam with
| Var v -> v.Length
| Abstraction _ -> 2
// â Not OK, code formatters will reformat to the above by default
match lam with
| Var v -> v.Length
| Abstraction _ -> 2
ããŒã¯ãŒã function ã䜿çšããŠå®è¡ããããã¿ãŒã³ ãããã³ã°ã§ã¯ãåã®è¡ã®å
é ãã 1 ã¬ãã« ã€ã³ãã³ãããå¿
èŠããããŸãã
// âïž OK
lambdaList
|> List.map (function
| Abs(x, body) -> 1 + sizeLambda 0 body
| App(lam1, lam2) -> sizeLambda (sizeLambda 0 lam1) lam2
| Var v -> 1)
éåžžãfunction ãŸã㯠let ã«ãã£ãŠå®çŸ©ããã颿°å
ã§ let rec ã䜿çšããããšã¯é¿ããmatch ãåªå
ããŠãã ããã 䜿çšããå Žåã¯ãfunction ããŒã¯ãŒãã«åããããã¿ãŒã³èŠåãæå®ããå¿
èŠããããŸãã
// âïž OK
let rec sizeLambda acc =
function
| Abs(x, body) -> sizeLambda (succ acc) body
| App(lam1, lam2) -> sizeLambda (sizeLambda acc lam1) lam2
| Var v -> succ acc
try/with åŒã®ãã©ãŒããã
äŸå€ã®çš®é¡ã®ãã¿ãŒã³ ãããã³ã°ã¯ãwith ãšåãã¬ãã«ã§ã€ã³ãã³ãããå¿
èŠããããŸãã
// âïž OK
try
if System.DateTime.Now.Second % 3 = 0 then
raise (new System.Exception())
else
raise (new System.ApplicationException())
with
| :? System.ApplicationException ->
printfn "A second that was not a multiple of 3"
| _ ->
printfn "A second that was a multiple of 3"
å¥ã 1 ã€ã ãã®å Žåãé€ããå¥ããšã« | ã远å ããŸãã
// âïž OK
try
persistState currentState
with ex ->
printfn "Something went wrong: %A" ex
// âïž OK
try
persistState currentState
with :? System.ApplicationException as ex ->
printfn "Something went wrong: %A" ex
// â Not OK, see above for preferred formatting
try
persistState currentState
with
| ex ->
printfn "Something went wrong: %A" ex
// â Not OK, see above for preferred formatting
try
persistState currentState
with
| :? System.ApplicationException as ex ->
printfn "Something went wrong: %A" ex
ååä»ãåŒæ°ã®ãã©ãŒããã
ååä»ãåŒæ°ã«ã¯ã= ãå²ãã¹ããŒã¹ãå¿
èŠã§ãã
// âïž OK
let makeStreamReader x = new System.IO.StreamReader(path = x)
// â Not OK, spaces are necessary around '=' for named arguments
let makeStreamReader x = new System.IO.StreamReader(path=x)
å€å¥å ±çšäœã䜿çšããŠãã¿ãŒã³ ãããã³ã°ãè¡ãå Žåãååä»ããã¿ãŒã³ã¯åæ§ã«æžåŒèšå®ãããŸãã以äžã«äŸã瀺ããŸãã
type Data =
| TwoParts of part1: string * part2: string
| OnePart of part1: string
// âïž OK
let examineData x =
match data with
| OnePartData(part1 = p1) -> p1
| TwoPartData(part1 = p1; part2 = p2) -> p1 + p2
// â Not OK, spaces are necessary around '=' for named pattern access
let examineData x =
match data with
| OnePartData(part1=p1) -> p1
| TwoPartData(part1=p1; part2=p2) -> p1 + p2
å€ååŒã®æŽåœ¢
éåžžã倿ŽåŒ location <- expr 㯠1 è¡ã§ãã©ãŒããããããŸãã
è€æ°è¡ã®ãã©ãŒããããå¿
èŠãªå Žåã¯ãå³åŽã®åŒãæ°ããè¡ã«é
眮ããŸãã
// âïž OK
ctx.Response.Headers[HeaderNames.ContentType] <-
Constants.jsonApiMediaType |> StringValues
ctx.Response.Headers[HeaderNames.ContentLength] <-
bytes.Length |> string |> StringValues
// â Not OK, code formatters will reformat to the above by default
ctx.Response.Headers[HeaderNames.ContentType] <- Constants.jsonApiMediaType
|> StringValues
ctx.Response.Headers[HeaderNames.ContentLength] <- bytes.Length
|> string
|> StringValues
ãªããžã§ã¯ãåŒã®æŽåœ¢
ãªããžã§ã¯ãåŒã®ã¡ã³ããŒã¯ãmember ã1ã¬ãã«ã€ã³ãã³ãããŠæŽåãããå¿
èŠããããŸãã
// âïž OK
let comparer =
{ new IComparer<string> with
member x.Compare(s1, s2) =
let rev (s: String) = new String (Array.rev (s.ToCharArray()))
let reversed = rev s1
reversed.CompareTo (rev s2) }
Stroustrup ã¹ã¿ã€ã«ã䜿çšããããšãã§ããŸãã
let comparer = {
new IComparer<string> with
member x.Compare(s1, s2) =
let rev (s: String) = new String(Array.rev (s.ToCharArray()))
let reversed = rev s1
reversed.CompareTo(rev s2)
}
空ã®åã®å®çŸ©ã¯ã1 è¡ã«æžåŒèšå®ã§ããŸãã
type AnEmptyType = class end
éžæããããŒãžå¹
ã«é¢ä¿ãªãã= class end ã¯åžžã«åãè¡ã«çœ®ãå¿
èŠããããŸãã
ã€ã³ããã¯ã¹ããã³ã¹ã©ã€ã¹åŒã®æžåŒèšå®
ã€ã³ããã¯ã¹åŒã«ã¯ãå·Šããã³å³è§ãã£ãã®ååŸã«ã¹ããŒã¹ãå«ããããšã¯ã§ããŸããã
// âïž OK
let v = expr[idx]
let y = myList[0..1]
// â Not OK
let v = expr[ idx ]
let y = myList[ 0 .. 1 ]
ããã¯ã以åã® expr.[idx] æ§æã«ãåœãŠã¯ãŸããŸãã
// âïž OK
let v = expr.[idx]
let y = myList.[0..1]
// â Not OK
let v = expr.[ idx ]
let y = myList.[ 0 .. 1 ]
åŒçšç¬Šã§å²ãŸããåŒã®æžåŒèšå®
åŒçšç¬Šã§å²ãŸããåŒãè€æ°è¡åŒã®å Žåã¯ãåºåãèšå· (<@ã @>ã <@@ã @@>) ãå¥ã
ã®è¡ã«é
眮ããå¿
èŠããããŸãã
// âïž OK
<@
let f x = x + 10
f 20
@>
// â Not OK
<@ let f x = x + 10
f 20
@>
åäžè¡ã®åŒã®å Žåãåºåãèšå·ã¯åŒèªäœãšåãè¡ã«é 眮ããå¿ èŠããããŸãã
// âïž OK
<@ 1 + 1 @>
// â Not OK
<@
1 + 1
@>
é£éåŒã®æžåŒèšå®
ãã§ãŒã³åŒ (. ãšçµ¡ã¿åã颿°ã¢ããªã±ãŒã·ã§ã³) ãé·ãå Žåã¯ãåã¢ããªã±ãŒã·ã§ã³åŒã³åºããæ¬¡ã®è¡ã«é
眮ããŸãã
ãã§ãŒã³å
ã®åŸç¶ã®ãªã³ã¯ããå
é ã®ãªã³ã¯ã®åŸã« 1 ã¬ãã« ã€ã³ãã³ãããŸãã
// âïž OK
Host
.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(fun webBuilder -> webBuilder.UseStartup<Startup>())
// âïž OK
Cli
.Wrap("git")
.WithArguments(arguments)
.WithWorkingDirectory(__SOURCE_DIRECTORY__)
.ExecuteBufferedAsync()
.Task
å é ã®ãªã³ã¯ã¯ãã·ã³ãã«ãªèå¥åã§ããå Žåãè€æ°ã®ãªã³ã¯ã§æ§æã§ããŸãã ããšãã°ãå®å šä¿®é£Ÿåå空éã®è¿œå ãªã©ã§ãã
// âïž OK
Microsoft.Extensions.Hosting.Host
.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(fun webBuilder -> webBuilder.UseStartup<Startup>())
åŸç¶ã®ãªã³ã¯ã«ã¯ã·ã³ãã«ãªèå¥åãå«ããå¿ èŠããããŸãã
// âïž OK
configuration.MinimumLevel
.Debug()
// Notice how `.WriteTo` does not need its own line.
.WriteTo.Logger(fun loggerConfiguration ->
loggerConfiguration.Enrich
.WithProperty("host", Environment.MachineName)
.Enrich.WithProperty("user", Environment.UserName)
.Enrich.WithProperty("application", context.HostingEnvironment.ApplicationName))
颿°ã¢ããªã±ãŒã·ã§ã³å ã®åŒæ°ãè¡ã®æ®ãã®éšåã«åãŸããªãå Žåã¯ãååŒæ°ã次ã®è¡ã«é 眮ããŸãã
// âïž OK
WebHostBuilder()
.UseKestrel()
.UseUrls("http://*:5000/")
.UseCustomCode(
longArgumentOne,
longArgumentTwo,
longArgumentThree,
longArgumentFour
)
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.Build()
// âïž OK
Cache.providedTypes
.GetOrAdd(cacheKey, addCache)
.Value
// â Not OK, formatting tools will reformat to the above
Cache
.providedTypes
.GetOrAdd(
cacheKey,
addCache
)
.Value
颿°ã¢ããªã±ãŒã·ã§ã³å
ã®ã©ã ãåŒæ°ã¯ã( ãšåãè¡ã«å§ããã¹ãã§ãã
// âïž OK
builder
.WithEnvironment()
.WithLogger(fun loggerConfiguration ->
// ...
())
// â Not OK, formatting tools will reformat to the above
builder
.WithEnvironment()
.WithLogger(
fun loggerConfiguration ->
// ...
())
宣èšã®ãã©ãŒããã
ãã®ã»ã¯ã·ã§ã³ã§ã¯ãããŸããŸãªçš®é¡ã®å®£èšã®ãã©ãŒãããã«ã€ããŠèª¬æããŸãã
宣èšã®éã«ç©ºçœè¡ã远å ãã
æäžäœã®é¢æ°ãšã¯ã©ã¹ã®å®çŸ©ã¯ã1 è¡ã®ç©ºçœè¡ã§åºåããŸãã æ¬¡ã«äŸã瀺ããŸãã
// âïž OK
let thing1 = 1+1
let thing2 = 1+2
let thing3 = 1+3
type ThisThat = This | That
// â Not OK
let thing1 = 1+1
let thing2 = 1+2
let thing3 = 1+3
type ThisThat = This | That
ã³ã³ã¹ãã©ã¯ãã« XML ããã¥ã¡ã³ã ã³ã¡ã³ããããå Žåã¯ãã³ã¡ã³ãã®åã«ç©ºçœè¡ã远å ããŸãã
// âïž OK
/// This is a function
let thisFunction() =
1 + 1
/// This is another function, note the blank line before this line
let thisFunction() =
1 + 1
let ãš member ã®å®£èšã®ãã©ãŒããã
let ãš member 宣èšããã©ãŒãããããå Žåãéåžžããã€ã³ãã£ã³ã°ã®å³åŽã¯ã1 è¡ã«åãããããããŸã㯠(é·ãããå Žåã¯) 1 ã¬ãã« ã€ã³ãã³ããããæ°ããè¡ã«ç§»åãããŸãã
ããšãã°ã次ã®äŸã¯æºæ ããŠããŸãã
// âïž OK
let a =
"""
foobar, long string
"""
// âïž OK
type File =
member this.SaveAsync(path: string) : Async<unit> =
async {
// IO operation
return ()
}
// âïž OK
let c =
{ Name = "Bilbo"
Age = 111
Region = "The Shire" }
// âïž OK
let d =
while f do
printfn "%A" x
ãããã¯éæºæ ã§ãã
// â Not OK, code formatters will reformat to the above by default
let a = """
foobar, long string
"""
let d = while f do
printfn "%A" x
ã¬ã³ãŒãåã®ã€ã³ã¹ã¿ã³ã¹åã§ã¯ããã£ããç¬èªã®è¡ã«é 眮ããããšãã§ããŸãã
// âïž OK
let bilbo =
{
Name = "Bilbo"
Age = 111
Region = "The Shire"
}
ãŸãããã€ã³ãåãšåãè¡ã«Stroustrupã®éå§ã¿ã°ããã{ã¹ã¿ã€ã«ã䜿çšããããšãã§ããŸãã
// âïž OK
let bilbo = {
Name = "Bilbo"
Age = 111
Region = "The Shire"
}
1 ã€ã®ç©ºçœè¡ãšããã¥ã¡ã³ãã§ã¡ã³ããŒãåºåããããã¥ã¡ã³ã ã³ã¡ã³ãã远å ããŸãã
// âïž OK
/// This is a thing
type ThisThing(value: int) =
/// Gets the value
member _.Value = value
/// Returns twice the value
member _.TwiceValue() = value*2
é¢é£ãã颿°ã®ã°ã«ãŒããåºåãããã«ã远å ã®ç©ºçœè¡ã (æ éã«) 䜿çšããããšãã§ããŸãã é¢é£ããäžé£ã®ã¯ã³ã©ã€ã㌠(äžé£ã®ãããŒå®è£ ãªã©) ã®éã§ã¯ã空çœè¡ãçç¥ããããšãã§ããŸãã 颿°å ã®è«çã»ã¯ã·ã§ã³ã瀺ãããã®ç©ºçœè¡ã¯æ éã«äœ¿çšããŠãã ããã
颿°ãšã¡ã³ããŒã®åŒæ°ã®ãã©ãŒããã
颿°ãå®çŸ©ãããšãã¯ãååŒæ°ã®ååŸã«ç©ºçœã䜿çšããŸãã
// âïž OK
let myFun (a: decimal) (b: int) c = a + b + c
// â Not OK, code formatters will reformat to the above by default
let myFunBad (a:decimal)(b:int)c = a + b + c
é·ã颿°å®çŸ©ãããå Žåã¯ããã©ã¡ãŒã¿ãŒãæ°ããè¡ã«é 眮ããããã«ç¶ããã©ã¡ãŒã¿ãŒã®ã€ã³ãã³ã ã¬ãã«ãäžèŽãããããã«ã€ã³ãã³ããèšå®ããŸãã
// âïž OK
module M =
let longFunctionWithLotsOfParameters
(aVeryLongParam: AVeryLongTypeThatYouNeedToUse)
(aSecondVeryLongParam: AVeryLongTypeThatYouNeedToUse)
(aThirdVeryLongParam: AVeryLongTypeThatYouNeedToUse)
=
// ... the body of the method follows
let longFunctionWithLotsOfParametersAndReturnType
(aVeryLongParam: AVeryLongTypeThatYouNeedToUse)
(aSecondVeryLongParam: AVeryLongTypeThatYouNeedToUse)
(aThirdVeryLongParam: AVeryLongTypeThatYouNeedToUse)
: ReturnType =
// ... the body of the method follows
let longFunctionWithLongTupleParameter
(
aVeryLongParam: AVeryLongTypeThatYouNeedToUse,
aSecondVeryLongParam: AVeryLongTypeThatYouNeedToUse,
aThirdVeryLongParam: AVeryLongTypeThatYouNeedToUse
) =
// ... the body of the method follows
let longFunctionWithLongTupleParameterAndReturnType
(
aVeryLongParam: AVeryLongTypeThatYouNeedToUse,
aSecondVeryLongParam: AVeryLongTypeThatYouNeedToUse,
aThirdVeryLongParam: AVeryLongTypeThatYouNeedToUse
) : ReturnType =
// ... the body of the method follows
ããã¯ãã¿ãã«ã䜿çšããã¡ã³ããŒãã³ã³ã¹ãã©ã¯ã¿ãŒãããã³ãã©ã¡ãŒã¿ãŒã«ã該åœããŸãã
// âïž OK
type TypeWithLongMethod() =
member _.LongMethodWithLotsOfParameters
(
aVeryLongParam: AVeryLongTypeThatYouNeedToUse,
aSecondVeryLongParam: AVeryLongTypeThatYouNeedToUse,
aThirdVeryLongParam: AVeryLongTypeThatYouNeedToUse
) =
// ... the body of the method
// âïž OK
type TypeWithLongConstructor
(
aVeryLongCtorParam: AVeryLongTypeThatYouNeedToUse,
aSecondVeryLongCtorParam: AVeryLongTypeThatYouNeedToUse,
aThirdVeryLongCtorParam: AVeryLongTypeThatYouNeedToUse
) =
// ... the body of the class follows
// âïž OK
type TypeWithLongSecondaryConstructor () =
new
(
aVeryLongCtorParam: AVeryLongTypeThatYouNeedToUse,
aSecondVeryLongCtorParam: AVeryLongTypeThatYouNeedToUse,
aThirdVeryLongCtorParam: AVeryLongTypeThatYouNeedToUse
) =
// ... the body of the constructor follows
ãã©ã¡ãŒã¿ãŒãã«ãªãŒåãããå Žåã¯ãæ°ããè¡ã«æ»ãå€ã®åãšå
±ã« = æåãé
眮ããŸãã
// âïž OK
type TypeWithLongCurriedMethods() =
member _.LongMethodWithLotsOfCurriedParamsAndReturnType
(aVeryLongParam: AVeryLongTypeThatYouNeedToUse)
(aSecondVeryLongParam: AVeryLongTypeThatYouNeedToUse)
(aThirdVeryLongParam: AVeryLongTypeThatYouNeedToUse)
: ReturnType =
// ... the body of the method
member _.LongMethodWithLotsOfCurriedParams
(aVeryLongParam: AVeryLongTypeThatYouNeedToUse)
(aSecondVeryLongParam: AVeryLongTypeThatYouNeedToUse)
(aThirdVeryLongParam: AVeryLongTypeThatYouNeedToUse)
=
// ... the body of the method
ããã¯ãé·ãããè¡ãåé¿ã (æ»ãå€ã®åã®ååãé·ãå ŽåããããŸã)ããã©ã¡ãŒã¿ãŒã远å ããéã®è¡ã®ç Žæãå°ãªãããããã®æ¹æ³ã§ãã
æŒç®å宣èšã®ãã©ãŒããã
æŒç®åã®å®çŸ©ãå²ãã«ã¯ãå¿ èŠã«å¿ããŠç©ºçœã䜿çšããŸãã
// âïž OK
let ( !> ) x f = f x
// âïž OK
let (!>) x f = f x
* ã§å§ãŸããè€æ°ã®æåãå«ãã«ã¹ã¿ã æŒç®åã«ã€ããŠã¯ãã³ã³ãã€ã©ã®ãããŸãããåé¿ããããã«ãå®çŸ©ã®å
é ã«ç©ºçœã远å ããå¿
èŠããããŸãã ãã®ããããã¹ãŠã®æŒç®åã®å®çŸ©ã 1 ã€ã®ç©ºçœæåã§å²ãããšããå§ãããŸãã
ã¬ã³ãŒã宣èšã®ãã©ãŒããã
ã¬ã³ãŒã宣èšã®å Žåãæ¢å®ã§ã¯ãåå®çŸ©ã® { ã 4 ã€ã®ã¹ããŒã¹ã§ã€ã³ãã³ãããåãè¡ã§ã©ãã« ãªã¹ããéå§ããã¡ã³ããŒãããå Žåã¯ã{ ããŒã¯ã³ã䜿çšããŠé
眮ããå¿
èŠããããŸãã
// âïž OK
type PostalAddress =
{ Address: string
City: string
Zip: string }
ãŸããã©ãã«ãããã« 4 ã€ã®ã¹ããŒã¹ã§ã€ã³ãã³ãããŠãç¬èªã®è¡ã«è§ãã£ããèšè¿°ããã®ãäžè¬çã§ãã
// âïž OK
type PostalAddress =
{
Address: string
City: string
Zip: string
}
åå®çŸ© ({ ã¹ã¿ã€ã«) ã®æåã®è¡ã®æ«å°Ÿã« Stroustrup ãé
眮ããããšãã§ããŸãã
// âïž OK
type PostalAddress = {
Address: string
City: string
Zip: string
}
远å ã®ã¡ã³ããŒãå¿
èŠãªå Žåã¯ãå¯èœãªéã with/end ã䜿çšããªãã§ãã ããã
// âïž OK
type PostalAddress =
{ Address: string
City: string
Zip: string }
member x.ZipAndCity = $"{x.Zip} {x.City}"
// â Not OK, code formatters will reformat to the above by default
type PostalAddress =
{ Address: string
City: string
Zip: string }
with
member x.ZipAndCity = $"{x.Zip} {x.City}"
end
// âïž OK
type PostalAddress =
{
Address: string
City: string
Zip: string
}
member x.ZipAndCity = $"{x.Zip} {x.City}"
// â Not OK, code formatters will reformat to the above by default
type PostalAddress =
{
Address: string
City: string
Zip: string
}
with
member x.ZipAndCity = $"{x.Zip} {x.City}"
end
ãã®ã¹ã¿ã€ã« ã«ãŒã«ã®äŸå€ã¯ãStroustrup ã¹ã¿ã€ã«ã«åŸã£ãŠã¬ã³ãŒãããã©ãŒãããããå Žåã§ãã ãã®ç¶æ³ã§ã¯ãã³ã³ãã€ã©èŠåã«ãããã€ã³ã¿ãŒãã§ã€ã¹ãå®è£
ããå Žåããããã«ã¡ã³ããŒã远å ããå Žåã¯ãwith ããŒã¯ãŒããå¿
èŠã§ãã
// âïž OK
type PostalAddress = {
Address: string
City: string
Zip: string
} with
member x.ZipAndCity = $"{x.Zip} {x.City}"
// â Not OK, this is currently invalid F# code
type PostalAddress = {
Address: string
City: string
Zip: string
}
member x.ZipAndCity = $"{x.Zip} {x.City}"
ã¬ã³ãŒã ãã£ãŒã«ãã« XML ããã¥ã¡ã³ãã远å ããå Žåã¯ãAligned ãŸã㯠Stroustrup ã¹ã¿ã€ã«ãåªå
ãããã¡ã³ããŒéã«ç©ºçœæåã远å ããå¿
èŠããããŸãã
// â Not OK - putting { and comments on the same line should be avoided
type PostalAddress =
{ /// The address
Address: string
/// The city
City: string
/// The zip code
Zip: string }
/// Format the zip code and the city
member x.ZipAndCity = $"{x.Zip} {x.City}"
// âïž OK
type PostalAddress =
{
/// The address
Address: string
/// The city
City: string
/// The zip code
Zip: string
}
/// Format the zip code and the city
member x.ZipAndCity = $"{x.Zip} {x.City}"
// âïž OK - Stroustrup Style
type PostalAddress = {
/// The address
Address: string
/// The city
City: string
/// The zip code
Zip: string
} with
/// Format the zip code and the city
member x.ZipAndCity = $"{x.Zip} {x.City}"
ã¬ã³ãŒãã§ã€ã³ã¿ãŒãã§ã€ã¹ã®å®è£ ãã¡ã³ããŒã宣èšããå Žåã¯ãéå§ããŒã¯ã³ãæ°ããè¡ã«é 眮ããçµäºããŒã¯ã³ãæ°ããè¡ã«é 眮ããããšããå§ãããŸãã
// âïž OK
// Declaring additional members on PostalAddress
type PostalAddress =
{
/// The address
Address: string
/// The city
City: string
/// The zip code
Zip: string
}
member x.ZipAndCity = $"{x.Zip} {x.City}"
// âïž OK
type MyRecord =
{
/// The record field
SomeField: int
}
interface IMyInterface
å¿åã¬ã³ãŒãåã®ãšã€ãªã¢ã¹ã«ã¯ããããã®åãèŠåãé©çšãããŸãã
å€å¥å ±çšäœå®£èšã®ãã©ãŒããã
å€å¥å
±çšäœå®£èšã®å Žåã¯ãåå®çŸ©ã® | ã 4 ã€ã®ã¹ããŒã¹ã§ã€ã³ãã³ãããŸãã
// âïž OK
type Volume =
| Liter of float
| FluidOunce of float
| ImperialPint of float
// â Not OK
type Volume =
| Liter of float
| USPint of float
| ImperialPint of float
çãå
±çšäœã 1 ã€ã®å Žåã¯ãå
é ã® | ãçç¥ã§ããŸãã
// âïž OK
type Address = Address of string
é·ãå
±çšäœãŸãã¯è€æ°è¡ã®å
±çšäœã®å Žåã¯ã| ãä¿æããåå
±çšäœã®ãã£ãŒã«ããæ°ããè¡ã«é
眮ããŸããåè¡ã®æ«å°Ÿã«ã¯åºåãã®ããã® * ãé
眮ãããŸãã
// âïž OK
[<NoEquality; NoComparison>]
type SynBinding =
| SynBinding of
accessibility: SynAccess option *
kind: SynBindingKind *
mustInline: bool *
isMutable: bool *
attributes: SynAttributes *
xmlDoc: PreXmlDoc *
valData: SynValData *
headPat: SynPat *
returnInfo: SynBindingReturnInfo option *
expr: SynExpr *
range: range *
seqPoint: DebugPointAtBinding
ããã¥ã¡ã³ã ã³ã¡ã³ãã远å ãããå Žåã¯ãå /// ã³ã¡ã³ãã®åã«ç©ºã®è¡ã䜿çšããŸãã
// âïž OK
/// The volume
type Volume =
/// The volume in liters
| Liter of float
/// The volume in fluid ounces
| FluidOunce of float
/// The volume in imperial pints
| ImperialPint of float
ãªãã©ã«å®£èšã®ãã©ãŒããã
F# ãªãã©ã«ã䜿çšããLiteral屿§ã¯ã屿§ãããèªäœã®è¡ã«é
眮ããPascalCase åœåã䜿çšããå¿
èŠããããŸãã
// âïž OK
[<Literal>]
let Path = __SOURCE_DIRECTORY__ + "/" + __SOURCE_FILE__
[<Literal>]
let MyUrl = "www.mywebsitethatiamworkingwith.com"
屿§ãå€ãšåãè¡ã«é 眮ããããšã¯é¿ããŠãã ããã
ã¢ãžã¥ãŒã«å®£èšã®ãã©ãŒããã
ããŒã«ã« ã¢ãžã¥ãŒã«å ã®ã³ãŒãã¯ãã¢ãžã¥ãŒã«ãåºæºãšããŠã€ã³ãã³ãããå¿ èŠããããŸãããæäžäœã®ã¢ãžã¥ãŒã«å ã®ã³ãŒãã¯ã€ã³ãã³ãããããšãã§ããŸããã åå空éèŠçŽ ãã€ã³ãã³ãããå¿ èŠã¯ãããŸããã
// âïž OK - A is a top-level module.
module A
let function1 a b = a - b * b
// âïž OK - A1 and A2 are local modules.
module A1 =
let function1 a b = a * a + b * b
module A2 =
let function2 a b = a * a - b * b
do 宣èšã®ãã©ãŒããã
å宣èšãã¢ãžã¥ãŒã«å®£èšãããã³ã³ã³ãã¥ããŒã·ã§ã³åŒã§ã¯ãå¯äœçšããã®æäœã«å¯Ÿã㊠do ãŸã㯠do! ã䜿çšããªããã°ãªããªãå ŽåããããŸãã
ããããè€æ°ã®è¡ã«ãŸãããå Žåã¯ãã€ã³ãã³ããšæ°ããè¡ã䜿çšããŠãã€ã³ãã³ããš let/let! ã®æŽåæ§ãç¶æããŸãã ã¯ã©ã¹ã§ do ã䜿ãäŸã以äžã«ç€ºããŸãã
// âïž OK
type Foo() =
let foo =
fooBarBaz
|> loremIpsumDolorSitAmet
|> theQuickBrownFoxJumpedOverTheLazyDog
do
fooBarBaz
|> loremIpsumDolorSitAmet
|> theQuickBrownFoxJumpedOverTheLazyDog
// â Not OK - notice the "do" expression is indented one space less than the `let` expression
type Foo() =
let foo =
fooBarBaz
|> loremIpsumDolorSitAmet
|> theQuickBrownFoxJumpedOverTheLazyDog
do fooBarBaz
|> loremIpsumDolorSitAmet
|> theQuickBrownFoxJumpedOverTheLazyDog
do! ãã¹ããŒã¹ 2 ã€ã§ã€ã³ãã³ãããäŸã§ã (do! ã§ã¯å¶ç¶ã«ããã¹ããŒã¹ 4 ã€ã§ã€ã³ãã³ãããããæ¹ãšã§ã¯éãããªããã)ã
// âïž OK
async {
let! foo =
fooBarBaz
|> loremIpsumDolorSitAmet
|> theQuickBrownFoxJumpedOverTheLazyDog
do!
fooBarBaz
|> loremIpsumDolorSitAmet
|> theQuickBrownFoxJumpedOverTheLazyDog
}
// â Not OK - notice the "do!" expression is indented two spaces more than the `let!` expression
async {
let! foo =
fooBarBaz
|> loremIpsumDolorSitAmet
|> theQuickBrownFoxJumpedOverTheLazyDog
do! fooBarBaz
|> loremIpsumDolorSitAmet
|> theQuickBrownFoxJumpedOverTheLazyDog
}
ã³ã³ãã¥ããŒã·ã§ã³åŒã®æŒç®ã®ãã©ãŒããã
ã³ã³ãã¥ããŒã·ã§ã³åŒã®ã«ã¹ã¿ã æäœãäœæããå Žåã¯ããã£ã¡ã«ã±ãŒã¹ã®ååä»ãã䜿çšããããšããå§ãããŸãã
// âïž OK
type MathBuilder() =
member _.Yield _ = 0
[<CustomOperation("addOne")>]
member _.AddOne (state: int) =
state + 1
[<CustomOperation("subtractOne")>]
member _.SubtractOne (state: int) =
state - 1
[<CustomOperation("divideBy")>]
member _.DivideBy (state: int, divisor: int) =
state / divisor
[<CustomOperation("multiplyBy")>]
member _.MultiplyBy (state: int, factor: int) =
state * factor
let math = MathBuilder()
let myNumber =
math {
addOne
addOne
addOne
subtractOne
divideBy 2
multiplyBy 10
}
ã¢ãã«åããããã¡ã€ã³ã¯ãæçµçã«ååä»ãèŠåãæ±ºå®ããã¹ãã§ãã å¥ã®èŠåã䜿çšããã®ãæ £çšçã§ããå Žåã¯ããã®èŠåã代ããã«äœ¿çšããå¿ èŠããããŸãã
åŒã®æ»ãå€ãã³ã³ãã¥ããŒã·ã§ã³åŒã®å Žåã¯ãã³ã³ãã¥ããŒã·ã§ã³åŒã®ããŒã¯ãŒãåãç¬èªã®è¡ã«é 眮ããããšããå§ãããŸãã
// âïž OK
let foo () =
async {
let! value = getValue()
do! somethingElse()
return! anotherOperation value
}
ã³ã³ãã¥ããŒã·ã§ã³åŒããã€ã³ãåãšåãè¡ã«é 眮ããããšãã§ããŸãã
// âïž OK
let foo () = async {
let! value = getValue()
do! somethingElse()
return! anotherOperation value
}
ã©ã®æ¹æ³ã䜿çšããŠããã³ãŒãããŒã¹å šäœã§äžè²«æ§ãä¿ã€ããšãç®æãå¿ èŠããããŸãã ãã©ãŒããã¿ã䜿çšãããšããã®èšå®ãäžè²«æ§ãç¶æããããã«æå®ã§ããŸãã
ã¿ã€ããšã¿ã€ã泚éã®ãã©ãŒããã
ãã®ã»ã¯ã·ã§ã³ã§ã¯ããã©ãŒãããã®çš®é¡ãšå泚éã«ã€ããŠèª¬æããŸãã ããã«ã¯ãæ¡åŒµåã .fsi ã®ã·ã°ãã㣠ãã¡ã€ã«ã®ãã©ãŒããããå«ãŸããŸãã
åã®å Žåã¯ããžã§ããªã㯠(Foo<T>) ã®åçœ®æ§æãåªå
ãã (ããã€ãã®ç¹å®ã®äŸå€ãã)
F# ã§ã¯ããžã§ããªãã¯åã®èšè¿°ã®åŸçœ®ã®ã¹ã¿ã€ã« (int list ãªã©) ãšãå眮ã®ã¹ã¿ã€ã« (list<int> ãªã©) ã®äž¡æ¹ãèš±å¯ããŠããŸãã
åŸçœ®ã®ã¹ã¿ã€ã«ã¯ã1 ã€ã®ååŒæ°ãšå
±ã«ã®ã¿äœ¿çšã§ããŸãã
6 ã€ã®ç¹å®ã®åãé€ããåžžã« .NET ã¹ã¿ã€ã«ãåªå
ããŸãã
- F# ãªã¹ãã®å Žåã¯ã
int listã§ã¯ãªãåŸçœ®åœ¢åŒlist<int>ã䜿çšããŸãã - F# ãªãã·ã§ã³ã®å Žåã¯ã
int optionã§ã¯ãªãåŸçœ®åœ¢åŒoption<int>ã䜿çšããŸãã - F# ã®å€ã®ãªãã·ã§ã³ã®å Žåã¯ã
int voptionã§ã¯ãªãåŸçœ®åœ¢åŒvoption<int>ã䜿çšããŸãã - F# é
åã®å Žåã¯ã
int arrayãarray<int>ã§ã¯ãªãåŸçœ®åœ¢åŒint[]ã䜿çšããŸãã - åç
§ã»ã«ã®å Žåã¯ã
int refãref<int>ã§ã¯ãªãRef<int>ã䜿çšããŸãã - F# ã·ãŒã±ã³ã¹ã®å Žåã¯ã
int seqã§ã¯ãªããåŸçœ®åœ¢åŒã®seq<int>ã䜿çšããŸãã
ãã以å€ã®ãã¹ãŠã®åã«ã¯ãå眮圢åŒã䜿çšããŸãã
颿°åã®ãã©ãŒããã
颿°ã®ã·ã°ããã£ãå®çŸ©ãããšãã¯ã-> ã·ã³ãã«ã®ååŸã«ç©ºçœã䜿çšããŸãã
// âïž OK
type MyFun = int -> int -> string
// â Not OK
type MyFunBad = int->int->string
åŒæ°ãšå€ã®åã«é¢ããæ³šéã®ãã©ãŒããã
åã®ã³ã¡ã³ããæã€å€ãŸãã¯åŒæ°ãå®çŸ©ããå Žåã¯ã: ã·ã³ãã«ã®åŸã«ç©ºçœã䜿çšããåã«ã¯äœ¿çšããŸããã
// âïž OK
let complexFunction (a: int) (b: int) c = a + b + c
let simpleValue: int = 0 // Type annotation for let-bound value
type C() =
member _.Property: int = 1
// â Not OK
let complexFunctionPoorlyAnnotated (a :int) (b :int) (c:int) = a + b + c
let simpleValuePoorlyAnnotated1:int = 1
let simpleValuePoorlyAnnotated2 :int = 2
è€æ°è¡ã®åã®æ³šéã®æžåŒèšå®
åã®æ³šéãé·ãããŸãã¯è€æ°è¡ã®ãšããæ¬¡ã®è¡ã«é 眮ãã1 ã¬ãã«ããšã«ã€ã³ãã³ãããŠãã ããã
type ExprFolder<'State> =
{ exprIntercept:
('State -> Expr -> 'State) -> ('State -> Expr -> 'State -> 'State -> Exp -> 'State }
let UpdateUI
(model:
#if NETCOREAPP2_1
ITreeModel
#else
TreeModel
#endif
)
(info: FileInfo) =
// code
()
let f
(x:
{|
a: Second
b: Metre
c: Kilogram
d: Ampere
e: Kelvin
f: Mole
g: Candela
|})
=
x.a
type Sample
(
input:
LongTupleItemTypeOneThing *
LongTupleItemTypeThingTwo *
LongTupleItemTypeThree *
LongThingFour *
LongThingFiveYow
) =
class
end
ã€ã³ã©ã€ã³å¿åã¬ã³ãŒãã®çš®é¡ã®å Žåã¯ãStroustrup ã¹ã¿ã€ã«ã䜿çšããããšãã§ããŸãã
let f
(x: {|
x: int
y: AReallyLongTypeThatIsMuchLongerThan40Characters
|})
=
x
æ»ãå€å泚éã®ãã©ãŒããã
颿°ãŸãã¯ã¡ã³ããŒã®æ»ãå€ã®åã®æ³šéã§ã¯ã: èšå·ã®ååŸã«ç©ºçœæåã䜿çšããŸãã
// âïž OK
let myFun (a: decimal) b c : decimal = a + b + c
type C() =
member _.SomeMethod(x: int) : int = 1
// â Not OK
let myFunBad (a: decimal) b c:decimal = a + b + c
let anotherFunBad (arg: int): unit = ()
type C() =
member _.SomeMethodBad(x: int): int = 1
眲åã®çš®é¡ã®ãã©ãŒããã
ã·ã°ããã£ã§å®å šãªé¢æ°åãèšè¿°ãããšãã¯ãåŒæ°ãè€æ°ã®è¡ã«åå²ããªããã°ãªããªãå ŽåããããŸãã æ»ãå€ã®åã¯åžžã«ã€ã³ãã³ããããŸãã
ã¿ãã«åœ¢åŒã®é¢æ°ã®å ŽåãåŒæ°ã¯ * ã§åºåããåè¡ã®æ«å°Ÿã«é
眮ããŸãã
äŸãšããŠã次ã®å®è£ ãå«ã颿°ã«ã€ããŠèããŠã¿ãŸãããã
let SampleTupledFunction(arg1, arg2, arg3, arg4) = ...
察å¿ããã·ã°ãã㣠ãã¡ã€ã« (æ¡åŒµå .fsi) ã§ã¯ãè€æ°è¡ã®ãã©ãŒããããå¿
èŠãªå Žåã«ã颿°ã次ã®ããã«ãã©ãŒãããã§ããŸãã
// âïž OK
val SampleTupledFunction:
arg1: string *
arg2: string *
arg3: int *
arg4: int ->
int list
åæ§ã«ãã«ãªãŒåããã颿°ã«ã€ããŠèããŠã¿ãŸãããã
let SampleCurriedFunction arg1 arg2 arg3 arg4 = ...
察å¿ããã·ã°ãã㣠ãã¡ã€ã«ã§ã¯ãåè¡ã®æ«å°Ÿã« -> ãé
眮ãããŸãã
// âïž OK
val SampleCurriedFunction:
arg1: string ->
arg2: string ->
arg3: int ->
arg4: int ->
int list
åæ§ã«ãã«ãªãŒåãããåŒæ°ãšã¿ãã«åœ¢åŒã®åŒæ°ã®çµã¿åãããåãåã颿°ã«ã€ããŠèããŠã¿ãŸãããã
// Typical call syntax:
let SampleMixedFunction
(arg1, arg2)
(arg3, arg4, arg5)
(arg6, arg7)
(arg8, arg9, arg10) = ..
察å¿ããã·ã°ãã㣠ãã¡ã€ã«ã§ã¯ãã¿ãã«ãå è¡ããåãã€ã³ãã³ããããŸã
// âïž OK
val SampleMixedFunction:
arg1: string *
arg2: string ->
arg3: string *
arg4: string *
arg5: TType ->
arg6: TType *
arg7: TType ->
arg8: TType *
arg9: TType *
arg10: TType ->
TType list
åãèŠåãåã·ã°ããã£ã®ã¡ã³ããŒã«é©çšãããŸãã
type SampleTypeName =
member ResolveDependencies:
arg1: string *
arg2: string ->
string
æç€ºçãªãžã§ããªãã¯ååŒæ°ãšå¶çŽã®ãã©ãŒããã
以äžã®ã¬ã€ãã©ã€ã³ã¯ã颿°å®çŸ©ãã¡ã³ããŒå®çŸ©ãããã³åå®çŸ©ãããã³é¢æ°é©çšã«é©çšãããŸãã
é·ãããªãå Žåã¯ããžã§ããªãã¯ååŒæ°ãšå¶çŽã¯ 1 ã€ã®è¡ã«åããŸãã
// âïž OK
let f<'T1, 'T2 when 'T1: equality and 'T2: comparison> param =
// function body
ãžã§ããªãã¯ååŒæ°/å¶çŽãšé¢æ°ãã©ã¡ãŒã¿ãŒã®äž¡æ¹ã¯åãŸããªãããåãã©ã¡ãŒã¿ãŒ/å¶çŽã®ã¿ã¯åãŸãå Žåããã©ã¡ãŒã¿ãŒã¯æ°ããè¡ã«é 眮ããŸãã
// âïž OK
let f<'T1, 'T2 when 'T1: equality and 'T2: comparison>
param
=
// function body
åãã©ã¡ãŒã¿ãŒãŸãã¯å¶çŽãé·ãããå Žåã¯ã次ã®ããã«åå²ããŠé
眮ããŸãã äžé£ã®åãã©ã¡ãŒã¿ãŒã¯ããã®é·ãã«é¢ãããã颿°ãšåãè¡ã«åããŸãã å¶çŽã®å Žåã¯ãwhen ãæåã®è¡ã«é
眮ãããã®é·ãã«é¢ãããåå¶çŽã 1 ã€ã®è¡ã«ä¿æããŸãã æåŸã®è¡ã®æ«å°Ÿã«ã¯ > ãé
眮ããŸãã å¶çŽã 1 ã¬ãã« ã€ã³ãã³ãããŸãã
// âïž OK
let inline f< ^T1, ^T2
when ^T1: (static member Foo1: unit -> ^T2)
and ^T2: (member Foo2: unit -> int)
and ^T2: (member Foo3: string -> ^T1 option)>
arg1
arg2
=
// function body
åãã©ã¡ãŒã¿ãŒ/å¶çŽã¯åå²ããããéåžžã®é¢æ°ãã©ã¡ãŒã¿ãŒããªãå Žåã¯ãé¢ä¿ãªãæ°ããè¡ã« = ãé
眮ããŸãã
// âïž OK
let inline f< ^T1, ^T2
when ^T1: (static member Foo1: unit -> ^T2)
and ^T2: (member Foo2: unit -> int)
and ^T2: (member Foo3: string -> ^T1 option)>
=
// function body
åãèŠåã颿°é©çšã«é©çšãããŸãã
// âïž OK
myObj
|> Json.serialize<
{| child: {| displayName: string; kind: string |}
newParent: {| id: string; displayName: string |}
requiresApproval: bool |}>
// âïž OK
Json.serialize<
{| child: {| displayName: string; kind: string |}
newParent: {| id: string; displayName: string |}
requiresApproval: bool |}>
myObj
ç¶æ¿ã®æžåŒèšå®
åºåºã¯ã©ã¹ã®ã³ã³ã¹ãã©ã¯ã¿ãŒã®åŒæ°ã¯ãinherit å¥ã®åŒæ°ãªã¹ãã«è¡šç€ºãããŸãã
æ°ããè¡ã« inherit å¥ãé
眮ãã1 ã¬ãã«ããšã«ã€ã³ãã³ãããŸãã
type MyClassBase(x: int) =
class
end
// âïž OK
type MyClassDerived(y: int) =
inherit MyClassBase(y * 2)
// â Not OK
type MyClassDerived(y: int) = inherit MyClassBase(y * 2)
ã³ã³ã¹ãã©ã¯ã¿ãŒãé·ãããŸãã¯è€æ°è¡ã®å Žåã¯ã次ã®è¡ã«é
眮ãã1 ã¬ãã«ããšã«ã€ã³ãã³ãããŸãã
è€æ°è¡é¢æ°ã¢ããªã±ãŒã·ã§ã³ã®èŠåã«åŸãããã®è€æ°è¡ã³ã³ã¹ãã©ã¯ã¿ãŒãæžåŒèšå®ããŸãã
type MyClassBase(x: string) =
class
end
// âïž OK
type MyClassDerived(y: string) =
inherit
MyClassBase(
"""
very long
string example
"""
)
// â Not OK
type MyClassDerived(y: string) =
inherit MyClassBase(
"""
very long
string example
""")
ãã©ã€ã㪠ã³ã³ã¹ãã©ã¯ã¿ãŒã®æžåŒèšå®
æ¢å®ã®æžåŒèšå®èŠåã§ã¯ããã©ã€ã㪠ã³ã³ã¹ãã©ã¯ã¿ãŒã®ååãšãã£ãã®éã«ã¹ããŒã¹ã¯è¿œå ãããŸããã
// âïž OK
type MyClass() =
class
end
type MyClassWithParams(x: int, y: int) =
class
end
// â Not OK
type MyClass () =
class
end
type MyClassWithParams (x: int, y: int) =
class
end
è€æ°ã®ã³ã³ã¹ãã©ã¯ã¿ãŒ
inherit å¥ãã¬ã³ãŒãã®äžéšã®ãšããçããã°åãè¡ã«é
眮ããŸãã
é·ãå Žåãè€æ°è¡ã®å Žåã¯ããã®è¡ã次ã®è¡ã«é
眮ãã1ã¬ãã«åã€ã³ãã³ãããŸãã
type BaseClass =
val string1: string
new () = { string1 = "" }
new (str) = { string1 = str }
type DerivedClass =
inherit BaseClass
val string2: string
new (str1, str2) = { inherit BaseClass(str1); string2 = str2 }
new () =
{ inherit
BaseClass(
"""
very long
string example
"""
)
string2 = str2 }
ãã©ãŒããã屿§
屿§ ã¯ã³ã³ã¹ãã©ã¯ãã®äžã«é 眮ãããŸãã
// âïž OK
[<SomeAttribute>]
type MyClass() = ...
// âïž OK
[<RequireQualifiedAccess>]
module M =
let f x = x
// âïž OK
[<Struct>]
type MyRecord =
{ Label1: int
Label2: string }
ãããã¯ãXML ããã¥ã¡ã³ãã®åŸã«é 眮ããå¿ èŠããããŸãã
// âïž OK
/// Module with some things in it.
[<RequireQualifiedAccess>]
module M =
let f x = x
ãã©ã¡ãŒã¿ãŒã®å±æ§ã®ãã©ãŒããã
屿§ã¯ããã©ã¡ãŒã¿ãŒã«ãé 眮ã§ããŸãã ãã®å Žåããthenãããã©ã¡ãŒã¿ãŒãšåãè¡ã§ååã®åã«é 眮ããŸãã
// âïž OK - defines a class that takes an optional value as input defaulting to false.
type C() =
member _.M([<Optional; DefaultParameterValue(false)>] doSomething: bool)
è€æ°ã®å±æ§ã®ãã©ãŒããã
ãã©ã¡ãŒã¿ãŒã§ã¯ãªãã³ã³ã¹ãã©ã¯ãã«è€æ°ã®å±æ§ãé©çšããå Žåã¯ãå屿§ãå¥ã ã®è¡ã«é 眮ããŸãã
// âïž OK
[<Struct>]
[<IsByRefLike>]
type MyRecord =
{ Label1: int
Label2: string }
ãã©ã¡ãŒã¿ãŒã«é©çšããå Žåã¯ãåãè¡ã«å±æ§ãé
眮ãã; åºåãèšå·ã§åºåããŸãã
è¬èŸ
ãããã®ã¬ã€ãã©ã€ã³ã¯ãAnh-Dung Phan ã«ãããA comprehensive guide to F# Formatting Conventions\(F# ã®æžåŒèŠåã«é¢ããå æ¬çãªã¬ã€ã)\ãã«åºã¥ããŠããŸãã