2012-10-02 28 views
7

我试图编写一个函数,它需要一个整数和一个三元组,并返回给定位置的三元组元素(练习5.3从Hickey的书中)。 Triplet应该能够包含不同类型的元素。我认为,如果我编写3个小函数,每个函数都返回三元组中的特定元素,并使我的大函数相应地返回其中的一个,那么它会执行这个技巧,但它不起作用。OCaml元组中的意外类型不匹配

我试图摆弄这个“eta扩展”的概念,但我没有得到它。

let nth1 (a, _, _) = a 
let nth2 (_, b, _) = b 
let nth3 (_, _, c) = c 

let nth i = match i with 
    | 1 -> nth1 
    | 2 -> nth2 
    | _ -> nth3 

let main = printf "%d\n" (nth 1 ("hello", 2, 'c')) 

所以它应该在这里写“2”。有什么建议?

+1

编辑,因为这不是真正的价值限制,称它这样会迷惑读者。 –

回答

6

在编写代码之前,通常会考虑类型。什么是你的功能的建议类型?

+0

嗯,我得到了像“int - >((a * b * c) - >(a或b或c))”,这显然是错误的......感谢您揭露错误! – user1714986

+0

我认为这是练习的要点。也许有点偷偷摸摸,但很好。 –

7

基本回答你的问题:

在OCaml中,该型系统的工作原理,将迫使nth只返回类型的方式。你想要的是类似交叉类型,但OCaml的静态类型语义将改为强制nth仅返回单个类型。其结果是你的元组必须退化为元素是相同类型的情况。

让我们考虑这种互动:

# let nth1 (a,_,_) =a;; 
val nth1 : 'a * 'b * 'c -> 'a = <fun> 
# let nth2 (_,b,_) = b;; 
val nth2 : 'a * 'b * 'c -> 'b = <fun> 
# let nth3 (_,_,c) = c;; 
val nth3 : 'a * 'b * 'c -> 'c = <fun> 
# let nth i = match i with 
     | 1 -> nth1 
     | 2 -> nth2 
     | _ -> nth3;; 
val nth : int -> 'a * 'a * 'a -> 'a = <fun> 

所以你的问题很奇怪,不是printf通话,因为,而是因为nth定义。相反,你可能会考虑制作一个独特的类型,这是这几种类型的组合。

事实上,您描述的行为类型有点像依赖类型,其中实际得到的类型取决于的输入值i。这当然应该是有问题的,因为依赖类型比在ML中看到的允许多态性更具表达力!

我会说,你可以实例元组的做到这一点,例如,你可以做一个类型:

type IntOrStringOrX = int | string | X 

,然后你可以相应地写下第n型的...

+0

谢谢你的帮助。我肯定会在以后看到类型和实例......这个问题在有关它们的实际章节之前就已经出现了。 – user1714986

+0

@ user1714986:有趣的..你能指点我一下书中的相关例子,它的做法是正确地做到这一点需要使用ocaml没有的精心打字的系统。 –

+0

是的,这本书被称为J.Hickey介绍的Objective Caml(在线链接http://courses.cms.caltech.edu/cs134/cs134b/book。pdf)练习5.3。理论部分是第5章的前两段。 – user1714986