F# 什么时候应该在函数中使用函数,而不是单独的私有函数?
什么时候应该在函数中使用函数,而不是单独的私有函数 我发现我编写的函数相当长:F# 什么时候应该在函数中使用函数,而不是单独的私有函数?,f#,F#,什么时候应该在函数中使用函数,而不是单独的私有函数 我发现我编写的函数相当长: let optionsFor piece (positions:Space list) = let yDirection = match piece with | Black _ -> -1 | Red _ -> 1 let sourceX , sourceY = match p
let optionsFor piece (positions:Space list) =
let yDirection = match piece with
| Black _ -> -1
| Red _ -> 1
let sourceX , sourceY =
match piece with
| Black (checker , pos) -> pos
| Red (checker , pos) -> pos
let optionsForPiece =
(fun pos -> pos = ((sourceX - 1) , (sourceY + yDirection)) ||
pos = ((sourceX + 1) , (sourceY + yDirection)))
let availableSelection =
(fun space -> match space with
| Available pos -> Some pos
| Allocated _ -> None)
let availablePositions =
positions |> List.filter toAvailable
|> List.choose availableSelection
availablePositions |> List.filter optionsForPiece
open NUnit.Framework
open FsUnit
(* Types *)
type Black = BlackKing | BlackSoldier
type Red = RedKing | RedSoldier
type Coordinate = int * int
type Piece =
| Black of Black * Coordinate
| Red of Red * Coordinate
type Space =
| Allocated of Piece
| Available of Coordinate
type Status =
| BlacksTurn | RedsTurn
| BlackWins | RedWins
(* Functions *)
let black coordinate = Allocated (Black (BlackSoldier , coordinate))
let red coordinate = Allocated (Red (RedSoldier , coordinate))
let startGame () =
[ red (0,0); red (2,0); red (4,0); red (6,0)
red (1,1); red (3,1); red (5,1); red (7,1)
red (0,2); red (2,2); red (4,2); red (6,2)
Available (1,3); Available (3,3); Available (5,3); Available (7,3)
Available (0,4); Available (2,4); Available (4,4); Available (6,4)
black (1,5); black (3,5); black (5,5); black (7,5)
black (0,6); black (2,6); black (4,6); black (6,6)
black (1,7); black (3,7); black (5,7); black (7,7) ] , BlacksTurn
let private toAvailable =
(fun space -> match space with
| Available pos -> true
| _ -> false)
let available (positions:Space list) = positions |> List.filter toAvailable
let optionsFor piece (positions:Space list) =
let yDirection = match piece with
| Black _ -> -1
| Red _ -> 1
let sourceX , sourceY =
match piece with
| Black (checker , pos) -> pos
| Red (checker , pos) -> pos
let optionsForPiece =
(fun pos -> pos = ((sourceX - 1) , (sourceY + yDirection)) ||
pos = ((sourceX + 1) , (sourceY + yDirection)))
let availableSelection =
(fun space -> match space with
| Available pos -> Some pos
| Allocated _ -> None)
let availablePositions =
positions |> List.filter toAvailable
|> List.choose availableSelection
availablePositions |> List.filter optionsForPiece
因此,我考虑将上述函数重构为几个小函数
但是,我不确定这在函数式编程中是否必要
当前关于内部函数与将其提取到私有函数的建议是什么
附录:
let optionsFor piece (positions:Space list) =
let yDirection = match piece with
| Black _ -> -1
| Red _ -> 1
let sourceX , sourceY =
match piece with
| Black (checker , pos) -> pos
| Red (checker , pos) -> pos
let optionsForPiece =
(fun pos -> pos = ((sourceX - 1) , (sourceY + yDirection)) ||
pos = ((sourceX + 1) , (sourceY + yDirection)))
let availableSelection =
(fun space -> match space with
| Available pos -> Some pos
| Allocated _ -> None)
let availablePositions =
positions |> List.filter toAvailable
|> List.choose availableSelection
availablePositions |> List.filter optionsForPiece
open NUnit.Framework
open FsUnit
(* Types *)
type Black = BlackKing | BlackSoldier
type Red = RedKing | RedSoldier
type Coordinate = int * int
type Piece =
| Black of Black * Coordinate
| Red of Red * Coordinate
type Space =
| Allocated of Piece
| Available of Coordinate
type Status =
| BlacksTurn | RedsTurn
| BlackWins | RedWins
(* Functions *)
let black coordinate = Allocated (Black (BlackSoldier , coordinate))
let red coordinate = Allocated (Red (RedSoldier , coordinate))
let startGame () =
[ red (0,0); red (2,0); red (4,0); red (6,0)
red (1,1); red (3,1); red (5,1); red (7,1)
red (0,2); red (2,2); red (4,2); red (6,2)
Available (1,3); Available (3,3); Available (5,3); Available (7,3)
Available (0,4); Available (2,4); Available (4,4); Available (6,4)
black (1,5); black (3,5); black (5,5); black (7,5)
black (0,6); black (2,6); black (4,6); black (6,6)
black (1,7); black (3,7); black (5,7); black (7,7) ] , BlacksTurn
let private toAvailable =
(fun space -> match space with
| Available pos -> true
| _ -> false)
let available (positions:Space list) = positions |> List.filter toAvailable
let optionsFor piece (positions:Space list) =
let yDirection = match piece with
| Black _ -> -1
| Red _ -> 1
let sourceX , sourceY =
match piece with
| Black (checker , pos) -> pos
| Red (checker , pos) -> pos
let optionsForPiece =
(fun pos -> pos = ((sourceX - 1) , (sourceY + yDirection)) ||
pos = ((sourceX + 1) , (sourceY + yDirection)))
let availableSelection =
(fun space -> match space with
| Available pos -> Some pos
| Allocated _ -> None)
let availablePositions =
positions |> List.filter toAvailable
|> List.choose availableSelection
availablePositions |> List.filter optionsForPiece
这是基于观点的,但我会给出我的观点 我的经验法则是,如果“helper”函数与“main”函数临时关联,我会将其作为嵌套函数编写。如果它们不是紧密关联的,我会将helper函数作为一个单独的函数来编写——甚至可能不会将其设置为私有函数,因为您永远不知道它何时会在不同模块中的其他代码中派上用场 紧密关联的内部函数的一个例子是一种带有累加器的循环函数,您经常在递归函数编程中编写这种循环函数。例如,下面是我为F#编程练习编写的一些代码:
module BinarySearchTree
type Node<'T> =
{ left: Node<'T> option
value: 'T
right: Node<'T> option }
let singleton v = { left = None; value = v; right = None }
let rec insert v t =
if v <= t.value
then match t.left with
| None -> { t with left = singleton v |> Some }
| Some n -> { t with left = insert v n |> Some }
else match t.right with
| None -> { t with right = singleton v |> Some }
| Some n -> { t with right = insert v n |> Some }
let fromList l =
match l with
| [] -> failwith "Can't create a tree from an empty list"
| hd::tl ->
tl |> List.fold (fun t v -> insert v t) (singleton hd)
let toList t =
let rec loop acc = function
| None -> acc
| Some node ->
(loop [] node.left) @ (node.value :: (loop [] node.right))
loop [] (Some t)
当您稍后重新访问代码时,可读性会大大提高,另外,在编写下一段代码时,您还可以使用更多可重用函数(如
可用的选择)。这是基于观点的,但我将提供我的观点
我的经验法则是,如果“helper”函数与“main”函数临时关联,我会将其作为嵌套函数编写。如果它们不是紧密关联的,我会将helper函数作为一个单独的函数来编写——甚至可能不会将其设置为私有函数,因为您永远不知道它何时会在不同模块中的其他代码中派上用场
紧密关联的内部函数的一个例子是一种带有累加器的循环函数,您经常在递归函数编程中编写这种循环函数。例如,下面是我为F#编程练习编写的一些代码:
module BinarySearchTree
type Node<'T> =
{ left: Node<'T> option
value: 'T
right: Node<'T> option }
let singleton v = { left = None; value = v; right = None }
let rec insert v t =
if v <= t.value
then match t.left with
| None -> { t with left = singleton v |> Some }
| Some n -> { t with left = insert v n |> Some }
else match t.right with
| None -> { t with right = singleton v |> Some }
| Some n -> { t with right = insert v n |> Some }
let fromList l =
match l with
| [] -> failwith "Can't create a tree from an empty list"
| hd::tl ->
tl |> List.fold (fun t v -> insert v t) (singleton hd)
let toList t =
let rec loop acc = function
| None -> acc
| Some node ->
(loop [] node.left) @ (node.value :: (loop [] node.right))
loop [] (Some t)
当您稍后重新访问代码时,可读性会提高很多,另外,在编写下一段代码时,您还可以使用更多可重用函数(如可用的选择
)。我想知道这是否更适合maybe。我的代码只是用作上下文。我认为这个问题甚至不需要代码。我想我正在寻找每个选项的优缺点。我不完全确定这是否是您所要求的,但这应该取决于您的使用情况,以及您是否愿意从外部访问函数(函数、模块和其他.NET代码)。定义许多小函数和内部函数并没有什么错,只要你组织它们。优点和缺点将高度依赖于上下文……我想知道这是否更适合于maybe。我的代码只是用作上下文。我认为这个问题甚至不需要代码。我想我正在寻找每个选项的优缺点。我不完全确定这是否是您所要求的,但这应该取决于您的使用情况,以及您是否愿意从外部访问函数(函数、模块和其他.NET代码)。定义许多小函数和内部函数并没有什么错,只要你组织它们就行。优点和缺点将高度依赖于上下文。。。。