F# 函数类型

F# function types

我正在练习 f# 并找到了这个示例,我必须在其中编写以下类型的 f# 函数:

fun1: 'a -> ('a -> 'b) -> 'b

fun2: ('a -> 'b) -> (('a -> 'c) -> 'd) -> ('b -> 'c) -> 'd

fun3: ('a -> 'b -> 'c) -> 'a * 'b -> 'c

fun4: ('a -> 'b -> 'a) -> 'a * 'b -> 'a

fun5: ('a -> 'a -> 'a) -> 'a * 'a -> 'a

我目前的解决方案

// fun1: ’a -> (’a -> ’b) -> ’b
let fun1 x k = k x

// fun2: (’a -> ’b) -> ((’a -> ’c) -> ’d) -> (’b -> ’c) -> ’d
let fun2 f t k = failwith "Not implemented"

// fun3: (’a -> ’b -> ’c) -> ’a * ’b -> ’c
let fun3 f (x, y) = f x y 

// fun4: (’a -> ’b -> ’a) -> ’a * ’b -> ’a
let fun4 f (x, y) = failwith "Not implemented"

// fun5: (’a -> ’a -> ’a) -> ’a * ’a -> ’a
let fun5 f (x, y) = failwith "Not implemented"

而且我已经成功完成了 fun1 和 fun 3,其他的需要帮助。任何人都可以给我一些提示吗?谢谢

我将添加一些提示而不是发布解决方案:

// fun2: (’a -> ’b) -> ((’a -> ’c) -> ’d) -> (’b -> ’c) -> ’d
let fun2 f t k = failwith "Not implemented"

这里,f'a -> 'b类型,k'b -> 'c类型。请注意,您可以组合这两个。这样,您就应该能够调用需要 'a -> 'c.

类型参数的函数 t
// fun5: (’a -> ’a -> ’a) -> ’a * ’a -> ’a
let fun5 f (x, y) = failwith "Not implemented"

这里,函数得到一个函数 f,可以用两个 'a 类型的参数调用它来产生 'a 类型的结果。您还有两个可以使用的参数,xy(作为元组传递)。该类型的结构与 fun3 中的结构非常相似,但如果您想在不使用类型注释的情况下编写此函数,您将需要以某种方式让编译器相信所有类型参数都是相同的,即, 'a。您可以通过多次调用 f 来做到这一点。如果你在一个地方调用 f x y 而在另一个地方调用 f y x,编译器就会知道 xy 的类型必须相同。

// fun4: (’a -> ’b -> ’a) -> ’a * ’b -> ’a
let fun4 f (x, y) = failwith "Not implemented"

这再次类似于 fun3fun4,但同样 - 要在没有类型注释的情况下执行此操作 - 您需要以某种方式说服编译器 f 与它 returns 的类型相同。执行此操作的最佳方法是将 f 的结果传递回 f(作为另一个调用中的第一个参数)。这迫使编译器统一类型。

重要的是你要理解你得到的执行,托马斯很好地解释了一切。 Anymay 这里有一些解决方案,你可以如何做到这一点。或者至少,我将如何解决它。

(* fun1: ’a -> (’a -> ’b) -> ’b *)
let fun1 x f =
    f x

(* fun2: (’a -> ’b) -> ((’a -> ’c) -> ’d) -> (’b -> ’c) -> ’d *)
let fun2 f h g =
    h (f >> g)

(* fun3: (’a -> ’b -> ’c) -> ’a * ’b -> ’c *)
let fun3 f (x,y) = 
    f x y

(* fun4: (’a -> ’b -> ’a) -> ’a * ’b -> ’a *)
let fun4 (f : 'a -> 'b -> 'a) (x,y) = 
    f x y

(* fun5: (’a -> ’a -> ’a) -> ’a * ’a -> ’a *)
let fun5 (f : 'a -> 'a -> 'a) (x,y) = 
    f x y

一样有趣side-note。 fun1 基本上是 F# 中的 |> 函数或运算符。

证明:

let add1 x = x + 1

printfn "%d" ((|>) 10 add1)
printfn "%d" (fun1 10 add1)