F# 如何在F中直接重用从另一个函数返回的函数#

F# 如何在F中直接重用从另一个函数返回的函数#,f#,F#,我目前正在从事一个项目,在这个项目中,我必须根据一些规则创建许多函数,并在以后重用这些函数。为此,我开始学习F,在F中似乎比在C中更自然 我成功地创建了应该创建的函数,但在重用它们时遇到了一些问题。下面是一个非常简单的例子,来说明我正在尝试做什么 let choice = 2 let fCreator (x:float) = match choice with |1 -> x * x |2 -> x * 10.0 |3 -> x + 20

我目前正在从事一个项目,在这个项目中,我必须根据一些规则创建许多函数,并在以后重用这些函数。为此,我开始学习F,在F中似乎比在C中更自然

我成功地创建了应该创建的函数,但在重用它们时遇到了一些问题。下面是一个非常简单的例子,来说明我正在尝试做什么

let choice = 2

let fCreator (x:float) =
    match choice with
    |1 ->  x * x
    |2 ->  x * 10.0
    |3 ->  x + 20.0
    |_ ->  x
我有一个全局变量选择,根据它,在fCreator中选择并返回x的转换。这可以称之为

let result1 = fCreator 1.0
但问题是,我必须对许多不同的输入使用所选的转换(在这种情况下是x*10),并且以这种方式使用它

let result2 = fCreator 2.0
let result3 = fCreator 3.0
.
.
.
然后整个选择过程再次完成,这在这里不是什么大问题,但我实际的选择函数要复杂得多,需要一些时间来计算

是否可以调用fCreator,获取并保存所选转换,然后直接使用它?差不多

let selectedFunction x:float = fCreator x:float
那在哪里呢

selectedFunction x:float = x * 10

我知道上面的方法是行不通的,但我希望你明白我在做什么。selectedFunction应该是从fCreator选择的转换

我对F#很陌生,所以我可能忽略了一些显而易见的东西,但根据F#中的函数缓存,我仔细阅读了几个Q&A。但就我所见,无论是回忆录还是懒散的评估都不能满足我的要求

我还尝试将fCreator编写为一个void函数,其中x作为声明但未初始化的变量,然后返回一个带有该变量的转换。但这并没有完全奏效,而且据我所知,这也不是F#的正确做法


我希望有人能给我一个提示。

不要依赖全局值,而是定义一个返回另一个函数的函数:

let selectCreator choice =
    match choice with
    | 1 -> fun x -> x * x
    | 2 -> fun x -> x * 10.0
    | 3 -> fun x -> x + 20.0
    | _ -> id
> let creator3 = selectCreator 3;;
3 selected
val creator3 : (float -> float)

> creator3 4.0;;
val it : float = 24.0
> creator3 5.0;;
val it : float = 25.0
这是一个返回所需函数的函数。它有签名
int->(float->float)
。您可以将其绑定到以下特定选项:

let creator = selectCreator 2
let choice = 2

let fCreator =
    match choice with
    | 1 -> fun x -> x * x
    | 2 -> fun x -> x * 10
    | 3 -> fun x -> x + 20
    | _ -> x
let mkCreator choice = function
    | 1 -> fun x -> x * x
    | 2 -> ( *) 10.0
    | 3 -> (+) 20.0
    | _ -> id

let fCreator = mkCreator 2
fCreator 20.0               (* val it = 200.0 : float *)
现在,您可以对各种值使用
creator

> creator 2.0;;
val it : float = 20.0
> creator 3.0;;
val it : float = 30.0
仅当您调用
selectCreator
时,选择才会发生;每次调用
creator
,只需调用返回的函数即可。这可以通过对
selectCreator
进行以下修改来说明:

let selectCreator choice =
    match choice with
    | 1 ->
        printf "1 selected"
        fun x -> x * x
    | 2 ->
        printf "2 selected"
        fun x -> x * 10.0
    | 3 ->
        printf "3 selected"
        fun x -> x + 20.0
    | _ ->
        printf "Default selected"
        id
虽然在函数式编程中,我们不喜欢副作用,但这是一个很好的方式来证明它是按预期工作的。以下是FSI会话的日志:

> let creator = selectCreator 2;;
2 selected
val creator : (float -> float)

> creator 4.0;;
val it : float = 40.0

> creator 5.0;;
val it : float = 50.0
请注意,它仅在选择
creator
时打印选择,而不是在调用它时打印

这种方法还有一个优点,即您在运行时改变主意,并选择不同的函数:

let selectCreator choice =
    match choice with
    | 1 -> fun x -> x * x
    | 2 -> fun x -> x * 10.0
    | 3 -> fun x -> x + 20.0
    | _ -> id
> let creator3 = selectCreator 3;;
3 selected
val creator3 : (float -> float)

> creator3 4.0;;
val it : float = 24.0
> creator3 5.0;;
val it : float = 25.0

定义一个返回另一个函数的函数,而不是依赖全局值:

let selectCreator choice =
    match choice with
    | 1 -> fun x -> x * x
    | 2 -> fun x -> x * 10.0
    | 3 -> fun x -> x + 20.0
    | _ -> id
> let creator3 = selectCreator 3;;
3 selected
val creator3 : (float -> float)

> creator3 4.0;;
val it : float = 24.0
> creator3 5.0;;
val it : float = 25.0
这是一个返回所需函数的函数。它有签名
int->(float->float)
。您可以将其绑定到以下特定选项:

let creator = selectCreator 2
let choice = 2

let fCreator =
    match choice with
    | 1 -> fun x -> x * x
    | 2 -> fun x -> x * 10
    | 3 -> fun x -> x + 20
    | _ -> x
let mkCreator choice = function
    | 1 -> fun x -> x * x
    | 2 -> ( *) 10.0
    | 3 -> (+) 20.0
    | _ -> id

let fCreator = mkCreator 2
fCreator 20.0               (* val it = 200.0 : float *)
现在,您可以对各种值使用
creator

> creator 2.0;;
val it : float = 20.0
> creator 3.0;;
val it : float = 30.0
仅当您调用
selectCreator
时,选择才会发生;每次调用
creator
,只需调用返回的函数即可。这可以通过对
selectCreator
进行以下修改来说明:

let selectCreator choice =
    match choice with
    | 1 ->
        printf "1 selected"
        fun x -> x * x
    | 2 ->
        printf "2 selected"
        fun x -> x * 10.0
    | 3 ->
        printf "3 selected"
        fun x -> x + 20.0
    | _ ->
        printf "Default selected"
        id
虽然在函数式编程中,我们不喜欢副作用,但这是一个很好的方式来证明它是按预期工作的。以下是FSI会话的日志:

> let creator = selectCreator 2;;
2 selected
val creator : (float -> float)

> creator 4.0;;
val it : float = 40.0

> creator 5.0;;
val it : float = 50.0
请注意,它仅在选择
creator
时打印选择,而不是在调用它时打印

这种方法还有一个优点,即您在运行时改变主意,并选择不同的函数:

let selectCreator choice =
    match choice with
    | 1 -> fun x -> x * x
    | 2 -> fun x -> x * 10.0
    | 3 -> fun x -> x + 20.0
    | _ -> id
> let creator3 = selectCreator 3;;
3 selected
val creator3 : (float -> float)

> creator3 4.0;;
val it : float = 24.0
> creator3 5.0;;
val it : float = 25.0

如果选择计算一次,然后始终相同,则可以执行以下操作:

let creator = selectCreator 2
let choice = 2

let fCreator =
    match choice with
    | 1 -> fun x -> x * x
    | 2 -> fun x -> x * 10
    | 3 -> fun x -> x + 20
    | _ -> x
let mkCreator choice = function
    | 1 -> fun x -> x * x
    | 2 -> ( *) 10.0
    | 3 -> (+) 20.0
    | _ -> id

let fCreator = mkCreator 2
fCreator 20.0               (* val it = 200.0 : float *)

这将返回一个完全不同的函数,具体取决于
选项的值

如果选择计算一次,然后始终相同,则可以执行以下操作:

let creator = selectCreator 2
let choice = 2

let fCreator =
    match choice with
    | 1 -> fun x -> x * x
    | 2 -> fun x -> x * 10
    | 3 -> fun x -> x + 20
    | _ -> x
let mkCreator choice = function
    | 1 -> fun x -> x * x
    | 2 -> ( *) 10.0
    | 3 -> (+) 20.0
    | _ -> id

let fCreator = mkCreator 2
fCreator 20.0               (* val it = 200.0 : float *)

这将返回一个完全不同的函数,具体取决于
选项的值

您的想法是正确的,重用“从另一个函数返回”的函数。您可以这样做:

let creator = selectCreator 2
let choice = 2

let fCreator =
    match choice with
    | 1 -> fun x -> x * x
    | 2 -> fun x -> x * 10
    | 3 -> fun x -> x + 20
    | _ -> x
let mkCreator choice = function
    | 1 -> fun x -> x * x
    | 2 -> ( *) 10.0
    | 3 -> (+) 20.0
    | _ -> id

let fCreator = mkCreator 2
fCreator 20.0               (* val it = 200.0 : float *)
这使得“昂贵的”
mkCreator
调用只发生一次


另一个答复建议如下:

let mkCreator choice x = function
    | 1 -> x * x
    | 2 -> (*) 10.0
    | 3 -> (+) 20.0
    | _ -> x

let fCreator = mkCreator 2

但是,
mkCreator
的主体在拥有所有参数之前不会被计算。这意味着您以后每次应用
fCreator
,都将评估
mkCreator
的主体。但这正是我们试图避免的

您的想法是正确的,重用“从另一个函数返回”的函数。您可以这样做:

let creator = selectCreator 2
let choice = 2

let fCreator =
    match choice with
    | 1 -> fun x -> x * x
    | 2 -> fun x -> x * 10
    | 3 -> fun x -> x + 20
    | _ -> x
let mkCreator choice = function
    | 1 -> fun x -> x * x
    | 2 -> ( *) 10.0
    | 3 -> (+) 20.0
    | _ -> id

let fCreator = mkCreator 2
fCreator 20.0               (* val it = 200.0 : float *)
这使得“昂贵的”
mkCreator
调用只发生一次


另一个答复建议如下:

let mkCreator choice x = function
    | 1 -> x * x
    | 2 -> (*) 10.0
    | 3 -> (+) 20.0
    | _ -> x

let fCreator = mkCreator 2

但是,
mkCreator
的主体在拥有所有参数之前不会被计算。这意味着您以后每次应用
fCreator
,都将评估
mkCreator
的主体。但这正是我们试图避免的

非常感谢大家的回复

所以总体思路是在我的选择函数中使用匿名函数作为返回值。在上面的例子中,这是一种非常简单的方法

但问题是(至少对我来说)在我的实际选择函数中,转换是通过大量递归函数调用创建的,这使得将它们定义为匿名函数不是那么容易。创建的转换(如上面的
x*x
)实际上是操作序列和递归函数,最好的办法是让它们保持不变

我希望仅通过更改调用选择函数的代码就可以存储所选转换。这样我就可以得到像