OCaml 和创建列表列表

Posted

技术标签:

【中文标题】OCaml 和创建列表列表【英文标题】:OCaml and creating a list of lists 【发布时间】:2014-03-11 20:33:27 【问题描述】:

我目前正在尝试使用函数来创建:

0  V12 V13 V14
V21 0  V23 V24
V31 V32 0  V34
V41 V42 V43 0

我发现这样做的一种方法是使用这些方程式:

(2*V1 - 1)*(2*V2-1) = for spot V(1,2) in the Matrix
(2*V1 - 1)*(2*V3-1) = for spot V(1,3) in the Matrix
etc

到目前为止,我有:

let singleState state = 
if state = 0.0 then 0.0
else
    ((2.0 *. state) -. 1.0);;


let rec matrixState v = 
match v with
| [] -> []
| hd :: [] -> v
| hd :: (nx :: _ as tl) ->
    singleState hd *. singleState nx :: matrixState tl;;

我的结果是:

float list = [-3.; -3.; -3.; -1.]

当它们应该是如下所示的列表时:

0 -1 1 -1
-1 0 -1 1
1 -1 0 -1
-1 1 -1 0 

因此,它不是列出列表,而是仅列出一个列表。我也很难弄清楚如何使对角线为 0。

签名应如下所示:

val singleState : float list -> float list list = <fun>
val matrixState : float list list -> float list list = <fun>

我得到了

val singleState : float -> float = <fun>
val matrixState : float list -> float list = <fun>

有什么想法吗?

【问题讨论】:

您使用的语言是“OCaml”,大写 O 和大写 C。caml.inria.fr/ocaml/index.en.html 【参考方案1】:

通过一些修复,您的函数将生成一行结果。然后你可以为你需要的每一行调用一次。进行重复调用的一个好方法可能是使用List.map

假设这主要是一个学习练习,最好先制作一个这样的矩阵:

V11 V12 V13 V14
V21 V22 V23 V24
V31 V32 V33 V34
V41 V42 V43 V44

我认为这会更容易计算。

然后你可以用零替换对角线。下面是一些可以替换对角线的代码:

let replnth r n l =
    List.mapi (fun i x -> if i = n then r else x) l

let zerorow row (n, res) =
    (n - 1, replnth 0.0 n row :: res)

let zerodiag m =
    let (_, res) = List.fold_right zerorow m (List.length m - 1, []) in
    res

【讨论】:

是的,这是一个练习,但它说不要使用列表。里面的功能会让它变得相当困难 如果这是一个练习,我无论如何都不想为你编写代码 :-) 你可以使用显式递归打开这些函数。或者您可以编写自己的列表函数版本。【参考方案2】:

我更愿意为您的工作配备一个数组。

一个很好用的函数是Array.init,它是这样工作的,

# Array.init 5 (fun x -> x);;  
- : int array = [|0; 1; 2; 3; 4|]  

我们注意到 5 扮演着我们数组大小的角色。

但是由于您想要一个矩阵,我们需要构建一个数组数组,它​​通过两次调用Array.init 来实现,最后一个嵌套在第一个中,

# Array.init 3 (fun row -> Array.init 3 (fun col -> row+col));;
- : int array array = [|[|0; 1; 2|]; [|1; 2; 3|]; [|2; 3; 4|]|]

注意,我将变量称为 rowcol 以表示它们对应于矩阵的行索引和列索引。

最后,由于您的公式使用参考向量 V 持有值 [|V1;V2;V3;V4|],我们需要创建一个并合并调用将其放入我们的矩阵构建器中,(数组tab的单元格n上的值可以像tab.(n-1)一样访问)

这最终将我们引向了工作示例,

let vect = [|1;2;3;4|] 

let built_matrix = 
  Array.init 4 (fun row -> 
    Array.init 4 (fun col -> 
      if col=row then 0
      else vect.(row)+vect.(col)))

当然,您必须根据自己的方便对其进行调整,以便根据您的要求匹配这段代码。

关于语法的旁注, 使用 OCaml 的一些不错的功能可以避免每次重复数组。 我们可以像这样在本地打开一个模块,

let built_matrix = 
 let open Array in 
   init 4 (fun row -> 
     init 4 (fun col -> 
       if col=row then 0
       else vect.(row)+vect.(col)))

更短,let open Array in ... 可以写成Array.(...),下面是一段代码解释下优秀的 utop 来说明它(我将利用这个机会来合并转换我们的矩阵到列表列表。)

utop # 
Array.(
  to_list 
  @@ map to_list 
  @@ init 4 (fun r -> 
     init 4 (fun c -> 
       if r = c then 0 
       else vect.(r)+ vect.(c))))
;;
- : int list list = [[0; 3; 4; 5]; [3; 0; 5; 6]; [4; 5; 0; 7]; [5; 6; 7; 0]]   

希望对你有帮助

【讨论】:

以上是关于OCaml 和创建列表列表的主要内容,如果未能解决你的问题,请参考以下文章

截断OCaml中的列表

从 Ocaml 中的列表列表中删除重复项?

OCaml和OCaml评估模型中的功能应用列表

如何在ocaml中将字符串转换为整数列表?

在 OCaml 中访问 (int * float) 列表中的浮点数

整数列表到整数 OCaml