25、声明序列:let mutable a = [] let f x = a <- (x :: a) f(1);; 会被 F# 接受。请解释原因。
这些声明不会被 F# 接受。声明 let mutable a = [] 将 a 绑定到多态表达式 mutable [] 的值,该表达式不被视为值表达式,此声明会被多态表达式使用限制所拒绝。因为 F# 会在函数使用前推断 f 的类型为 'a -> unit ,后续调用 f 时可能会出现类型错误,如 f(1) 和 f("ab") 类型检查虽能通过,但在计算 f("ab") 时会出现非法表达式 "ab"::[1] 。
26、使用 while 循环声明一个用于计算斐波那契数 Fn 的函数。提示:引入变量来存储先前计算的两个斐波那契数。
以下是使用 while 循环实现计算斐波那契数 $ F_n $ 的 F# 代码:
let fibonacci n =
if n = 0 then 0
elif n = 1 then 1
else
let mutable prev1 = 0
let mutable prev2 = 1
let mutable current = 0
let mutable i = 2
while i <= n do
current <- prev1 + prev2
prev1 <- prev2
prev2 <- current
i <- i + 1
current
注:原答案中赋值语句使用了
=是错误的,在 F# 里可变变量赋值要用<-。
27、考虑以下列表生成函数:let rec bigListK n k = if n=0 then k [] else bigListK (n-1) (fun res -> 1::k(res));; 调用 bigListK 130000 id 会导致栈溢出。分析这个问题。
该函数不是尾递归函数,每次递归调用都会在栈上创建一个新的栈帧。调用 bigListK 130000 id 时,会创建 130000 个连续的栈帧,超过了栈的最大容量,从而导致栈溢出。
对比来看,像 bigListA 这样的尾递归函数能避免栈溢出问题,它在内存不足时是因为堆耗尽。
28、考虑如下 bld.Delay 声明的“替代方案”: type MaybeClass() = ... member bld.Delay f:maybe<’a> = delay(start (f()));; 这个新声明无法达到预期效果。请解释原因。
预期效果是让 maybe{ce} 形式的表达式表示真正的配方,实际烹饪延迟到配方启动时。新声明中 delay(start (f())) 先对 f() 进行了 start 操作,这会提前执行 f() 中的计算,而不是延迟到 start 函数调用时,所以无法延迟计算,不能达到预期效果。
29、以下用于非空数字列表的文法使用了左递归:numberList ::= number | numberList number。一个严格遵循此文法结构的解析器如下:let rec numberLst = parser {let! n = number return [n] } <|> parser {let! ns = numberLst let! n = number return ns @ [n]};; 该解析器存在问题。分析该解析器并解释问题所在。
由于文法使用了左递归,对应的解析器会进入无限循环,无法正常工作。
30、解释使用左递归的表达式语法存在的问题。
该语法里 expr 能扩展为 expr addOp term , term 也有类似情况,存在左递归。虽然理论上表达式推导步骤和构建表达式树步骤对应,但对应解析器会进入无限循环,所以不能用于此方法。
31、声明一个解析器组合器:pFold : (‘a -> ‘d -> ‘a) -> parser<’d> -> parser<’a> -> parser<’a>,使得如果 p 首先捕获值 a,之后重复使用 t 捕获值 d1, d2, …, dk,那么 pFold f t p 捕获值 a, a1 = f a d1, a2 = f a1 d2, …, ak = f ak−1 dk。使用这个解析器组合器以如下形式对 infixL 进行替代声明:let infixL op q p = pFold (fun … ) (pairOf op q) p ;;
以下是 pFold 解析器组合器的声明以及使用它对 infixL 进行替代声明的代码:

最低0.47元/天 解锁文章

被折叠的 条评论
为什么被折叠?



