在函数式编程中,当我认为可变时我认为是堆,并且当尝试编写功能更强大的代码时,您应该使用堆栈而不是堆。
那么,如何将值放入堆栈以供函数使用?
让 result01 = List.filter (fun x -> x % 2 = 0) [0;1;2;3;4;5]
这里的函数和值列表都被硬编码到 List.filter 参数中。
let divisibleBy2 = fun x -> x % 2 = 0
let values = [0;1;2;3;4;5]
let result02 = List.filter divisibleBy2 values
这里 list.filter 的函数参数绑定到 divisibleBy2 并且 list.filter 的列表参数绑定到值。
let result03 =
[0;1;2;3;4;5]
|> List.filter divisibleBy2
这里 list.filter 的 list 参数被转发到 list.filter 函数中。
let result04 =
[ for i in 1 .. 5 -> i]
|> List.filter divisibleBy2
既然我们已经在堆栈上拥有了所有数据,那么我们如何仅使用堆栈来处理数据?
函数式编程经常使用的模式之一是将数据放入一个结构中,然后使用递归函数一次处理一个项目。结构可以是列表、树、图等,通常使用可区分的联合来定义。具有一个或多个自引用的数据结构通常与递归函数一起使用。
所以这是一个示例,我们获取一个列表并将所有值乘以 2,然后在我们进行时将结果放回堆栈。堆栈上保存新值的变量是accumulator。
let mult2 values =
let rec mult2withAccumulator values accumulator =
match values with
| headValue::tailValues ->
let newValue = headValue * 2
let accumulator = newValue :: accumulator
mult2withAccumulator tailValues accumulator
| [] ->
List.rev accumulator
mult2withAccumulator values []
我们为此使用了一个累加器,它是一个函数的参数并且未定义的可变变量存储在堆栈中。此方法也使用模式匹配和列表区分联合。累加器在我们处理输入列表中的项目时保存新值,然后当列表中没有更多项目 ([]) 时,我们只需反转列表以获得正确顺序的新列表,因为新项目是连接的到accumulator的头。
要了解列表的数据结构(可区分联合),您需要查看它,所以这里是
type list =
| Item of 'a * List
| Empty
注意项目定义的结尾是List 引用自身,并且列表可以是一个空列表,当与模式匹配一起使用时是[]。
如何构建列表的简单示例是
empty list - []
list with one int value - 1::[]
list with two int values - 1::2::[]
list with three int values - 1::2::3::[]
这是定义了所有类型的同一个函数。
let mult2 (values : int list) =
let rec mult2withAccumulator (values : int list) (accumulator : int list) =
match (values : int list) with
| (headValue : int)::(tailValues : int list) ->
let (newValue : int) = headValue * 2
let (accumulator : int list) =
(((newValue : int) :: (accumulator : int list)) : int list)
mult2withAccumulator tailValues accumulator
| [] ->
((List.rev accumulator) : int list)
mult2withAccumulator values []
因此,将值放入堆栈并使用带有模式匹配的自引用可区分联合将有助于解决函数式编程的许多问题。