Functional programming 编写OCaml函数的正确且流畅的方法是什么?

Functional programming 编写OCaml函数的正确且流畅的方法是什么?,functional-programming,ocaml,Functional Programming,Ocaml,我在学习 在我学习了第三章之后,我似乎明白了let和fun是如何工作的。但是,我仍然很难写出自己的fun 这是我面临的一个问题示例 编写一个函数和,给定两个整数界限n和m以及一个函数 f、 计算总和(不允许循环)。i、 例如,和n m f=f(n)+f(n+1)+…+f(m) 那么,我应该如何开始考虑生成这个函数和? 在Java或普通编程语言中,这很容易 因为这里不允许for循环,所以我想我应该用let rec的方式来做 大概是这样的: let rec sum n m f=fun i->..

我在学习

在我学习了第三章之后,我似乎明白了
let
fun
是如何工作的。但是,我仍然很难写出自己的
fun


这是我面临的一个问题示例

编写一个函数和,给定两个整数界限n和m以及一个函数
f、 计算总和(不允许循环)。i、 例如,和n m f=f(n)+f(n+1)+…+f(m)


那么,我应该如何开始考虑生成这个函数和?

在Java或普通编程语言中,这很容易

因为这里不允许for循环,所以我想我应该用
let rec
的方式来做

大概是这样的:

let rec sum n m f=fun i->..

我需要一个
I
作为光标

不管怎样,我不能继续思考了

有人能为我指出一条路,让我玩得开心吗?


这是我的最终解决方案:

let rec sum n m f=if n int)->'b
但表达式应为int类型


为什么?“a”是什么?

你犯了一个典型的语法错误:
sumn+1mf
被解析为
(sumn)+(1nf)
。在OCaml中,函数应用程序(空格)比中缀运算符具有更强的优先级


类型错误的原因是
sum n
(在sum中使用)不是整数。它还需要一个参数(
m
)和一个返回整数的函数。在类型推断过程的这一点上(当错误发生时),OCaml将其表示为
'a->('a->int)->'b
:获取一些未知的内容
a
,一个从
a
到int的函数,并返回一些内容
b

类似于Java中的泛型。例如:
让测试a=1
它的类型是
'a->int
无论参数的类型如何,此函数都将返回1

错误是您需要在此处插入括号
(总和(n+1)mf)


Ocaml将其视为额外的参数,因此它产生的类型与您预期的不同。插入括号可以确保参数的数量正确。当您有很多代码时,调试是一个微妙的问题。因此,在类似情况下使用括号可以节省大量时间。:)

我希望这将帮助您从递归的角度而不是循环的角度来思考(让我们暂时忽略尾部递归)

所以你需要计算
f(n)+f(n+1)+。。。f(m)
。它可能会帮助您以一种归纳的方式思考这个问题。也就是说,假设您知道如何计算
f(n+1)+…+f(m)
,那么您需要做什么来计算原始结果?那么,您只需将
f(n)
添加到后者,对吗?这正是您的代码要说的:

let rec sum n m f =
  if n = m then
    f m
  else
    f n + sum (n + 1) m f;; (* here's the inductive step *)
您可以看到我如何将
f(n)
添加到
f(n+1)+的结果中f(m)
。因此,从归纳的角度思考,将问题分解为更小的部分,并思考如何将这些小部分的结果组合在一起


希望我没有把事情弄得更混乱。

FYI如果你用OCaml编程,你就再也不应该考虑循环了:即使循环对
let rec
表达式来说也是语法上的甜点。@KristopherMicinski所以OCaml总是喜欢rec?是的,这是做任何递归的函数方法。在OCaml的情况下,最好使用尾部递归函数,它不会建立堆栈框架。永远不要再使用循环(除非你真的明白它们是语法糖,并且你有充分的理由更喜欢它们而不是递归)。@KristopherMicinski我的解决方案不是尾部递归的,对吧?是的,谢谢,我把它改成了
sum(n+1)mf
,它现在可以正常工作了。但是你能告诉我在制作一个
有趣的
时该如何思考吗?该逻辑与其他简易编程语言有很大不同。@JacksonTale这样做并没有在注释中解释,而是通过做一段时间的函数式程序员并强迫自己完成一些示例来解释。让rec sum1 n m f=sum2 n m 0和sum2 n m s=如果n是,其思想是使用累加器来跟踪到目前为止计算的总和。因此,在进行计算时,您正在累积总和。。。因此,最后您可以简单地返回累积值。这避免了对子问题返回的结果进行操作(即,您可以立即返回子问题的结果)。