我是OCaml的新手,我想将高斯消除作为练习来实现。我可以使用有状态算法轻松完成它,这意味着在内存中保留一个矩阵,并通过传递对它的引用来递归地操作它。
然而,这种状态有点强制性的编程。我知道OCaml有能力做到这一点,但是我想问一下我是否有一些我没有想过的聪明的功能方式。
答案 0 :(得分:4)
您可以使用Map
来模拟矩阵。键是一对引用行和列的整数。您需要使用自己的get x y
函数来确保x < n
和y < n
,而不是直接访问Map
。 (编辑)您可以直接使用Pervasives
中的比较功能。
module OrderedPairs = struct
type t = int * int
let compare = Pervasives.compare
end
module Pairs = Map.Make (OrderedPairs)
let get_ n set x y =
assert( x < n && y < n );
Pairs.find (x,y) set
let set_ n set x y v =
assert( x < n && y < n );
Pairs.add (x,y) set v
实际上,在没有指定实现的情况下,拥有一组通用的函数(get x y
和set x y
至少)将是一个更好的选择。然后可以将函数传递给函数,或者通过仿函数在模块中实现(一个更好的解决方案,但是由于您刚接触OCaml,因此只需执行一些函数即可完成第一步)。通过这种方式,您可以使用Map
,Array
,Hashtbl
或一组函数来访问硬盘驱动器上的文件,以便在需要时实现矩阵。这是函数式编程的重要方面;你信任界面而不是利用副作用,而不用担心底层实现 - 因为它被认为是纯粹的。
答案 1 :(得分:4)
OCaml数组是可变的,并且很难避免像命令式语言中的数组那样对待它们。
Haskell具有不可变数组,但是从我对Haskell的(有限)经验来看,在大多数情况下,最终会切换到monadic,mutable数组。对于某些特定目的,不可变数组可能是惊人的。我一直想象你可以在Haskell中编写一个漂亮的动态编程实现,其中数组条目之间的依赖关系完全由它们中的表达式定义。关键是你真的只需要指定一次每个数组条目的内容。我不认为高斯消除遵循这种模式,因此它似乎不适合不可变数组。然而,看看它是如何工作的将会很有趣。
答案 2 :(得分:3)
到目前为止,答案是使用/模拟可变数据类型,但功能方法是什么样的?
要看,让我们将问题分解为一些功能组件:
高斯消除涉及一系列行操作,因此首先定义一个取2行和缩放因子的函数,然后返回结果行操作结果。
我们想要的行操作应该从特定行中消除变量(列),因此我们定义一个函数,该函数接受一对行和一个列索引,并使用先前定义的行操作返回该列的已修改行进入零。
然后我们定义两个函数,一个用于将矩阵转换为三角形,另一个用于将三角矩阵替换为对角形式(使用先前定义的函数),依次消除每列。我们可以迭代或递归列,矩阵可以定义为列表,向量或列表,向量或数组的数组。输入没有改变,但返回了一个修改过的矩阵,所以我们最终可以做到:
让out_matrix = to_diagonal(to_triangular in_matrix);
使它起作用的不是数据类型(数组或列表)是否可变,而是它们如何被使用。这种方法可能不是特别“聪明”或者是在OCaml中进行高斯消除的最有效方法,但使用纯函数可以让你干净地表达算法。