OCaml中的编程风格

时间:2014-05-17 13:20:16

标签: haskell functional-programming ocaml

我对编写高效功能程序的正确方法有疑问。假设我给出了一个正整数的列表,我想找到最小元素(如果为空则只需0)。然后,执行此操作的通用功能程序看起来像

minList s =
    | [] -> undefined
    | [x] -> x
    | x :: t -> min x (minList t) 

在一种惰性语言中,可以通过添加一个额外的子句来提高效率,如果找到零则终止递归 - 这样s只计算到第一个零

minList s = 
    | [] -> undefined
    | [x] -> x
    | x :: t -> if x==0 then 0 else min x (minList t)

但是,我认为这种技巧在OCaml之类的严格评估语言中是行不通的,我会在运行minList之前评估整个s?如果是这样,在OCaml中优化它的正确方法是什么?

其他问题:好的,如果我理解,如果陈述总是很懒惰的话。但是下面呢,例如:我再次在int列表上有一个函数,它首先检查第i个元素是否为零,即

f s = if s(i)==0 then 0 else g s

这里输入序列s出现在if语句的两个子句中,但显然对于有效的计算,你只想在第一种情况下评估s(i)。在这里,OCaml总会评估所有s,即使第一种情况成功吗?

4 个答案:

答案 0 :(得分:2)

ocaml中的

if个表达式不遵循严格的评估规则。 喜欢||和&&,懒得评价。 请看这个链接:if expressions

答案 1 :(得分:1)

在严格评估的语言中,将评估整个列表s。不过,

minList s = 
    | [] -> 0
    | x :: t -> if x==0 then 0 else min x (minList t)
如果找到0

将不会扫描整个列表。

if构造具有“非严格”语义,因为它只评估一个分支,而不是两者。这适用于严格和非严格的语言。

实际差异在于调用“用户定义的if”,例如(使用Haskell语法):

myIf :: Bool -> a -> a
myIf b x y = if b then x else y

使用非严格的语言,调用myIf True 3 (nonTerminatingFunction ())会产生3,而在严格的语言中,相同的表达式将永远循环。

答案 2 :(得分:1)

首先,空列表的最小值是未定义的,而不是0。这是有道理的,否则minList [1,2,3]将是0,这显然不正确。这就是ghci所说的:

Prelude> minimum []
*** Exception: Prelude.minimum: empty list

因此,您的功能应写为:

let minList (x::t) = min x (minList t)

这个定义存在一些问题:

  1. 它仍然会出错,因为空列表没有模式匹配。
  2. 这不是尾递归。
  3. 如果头部为0,则不会停止。
  4. 所以这是一个更好的解决方案:

    let minimum x xs = match x,xs
      | 0,xs        -> 0
      | x,[]        -> x
      | x,(y :: ys) -> minimum (min x y) ys
    
    let minList = function
      | [] -> raise Failure "No minimum of empty list"
      | x::t -> minimum x t
    

    这样编写它的好处是minimum是尾递归的。因此它不会增加堆栈大小。此外,如果头部为0,则会立即返回0

    懒惰的评价在这里没有发挥作用。

答案 3 :(得分:0)

几乎所有现代编程语言:

对于expr1 && expr2,如果expr1已经为假,则不会评估expr2。

对于expr1 || expr2,如果expr1已经为真,则不会对expr2进行评估。

OCaml也是这样做的。