F# 中的捕获计数
Captured count in F#
我是一名长期的 C# 开发人员,并试图掌握 F# 并为此我想做一个小项目,我需要以下内容:
是否可以创建具有以下行为的函数以及如何创建?注意:我知道 ref
可能可行,但我希望它更 "pure" 实用。
let count (x:int) (y:iny): (int -> int * int) =
??
let myCount = count 1
// --------
let myCount, value = myCount 2;; // value is now 3
let myCount, value = myCount 3;; // value is now 6
let myCount, value = myCount 1;; // value is now 7
您提供的 类型签名 不可能(因为您 return 一个包含两个整数的元组,但显然第一个应该再次具有相同的签名因为 count 1
本身是不可能的 - 你必须以某种方式包装它)。
但是根据你的例子,我认为你想要的应该是可能的:
这是一个与您的略有不同的版本,但我想您明白了:
type Counter = { value : int; update : int -> Counter }
let rec counter init =
{ value = init; update = fun upd -> counter (upd+init) }
这是实际操作:
> let myCounter = counter 1;;
val myCounter : Counter = {value = 1;
update = <fun:counter@118>;}
> let myCounter = myCounter.update 2;;
val myCounter : Counter = {value = 3;
update = <fun:counter@118>;}
> let myCounter = myCounter.update 3;;
val myCounter : Counter = {value = 6;
update = <fun:counter@118>;}
> let myCounter = myCounter.update 1;;
val myCounter : Counter = {value = 7;
update = <fun:counter@118>;}
对你来说够近了吗?
当然,如果你放弃纯粹,你可以让这种方式更简单(在 F# 中做这样的事情确实很常见):
let counter init =
let value = ref init
fun upd ->
value := !value + upd
!value
这是你的例子
> let myCounter = counter 1;;
val myCounter : (int -> int)
> myCounter 2;;
val it : int = 3
> myCounter 3;;
val it : int = 6
> myCounter 1;;
val it : int = 7
既然你提"pure functional"我就提"state monad"...
和 "update" 结合了更多:http://tomasp.net/blog/2014/update-monads/
做一些代码示例需要以下必要条件:将 fsharpx.extras 添加到为此代码制作的某个项目中。
#r @"..\packages\FSharpx.Extras.1.10.2\lib\FSharpx.Extras.dll"
open FSharpx.State
open System
let myCount value =
state {
let! s = getState
do! putState (s + value)
return s
}
let myNewCountWithTotalResult =
state {
let! _ = myCount 1
let! _ = myCount 2
let! _ = myCount 3
let! _ = myCount 1
return ()
}
printfn "My total with 0 as initial state is: %A" (exec myNewCountWithTotalResult 0)
//Just for the hell of it if you wanna initiate the state with something other than 0
//to get a totally different result
printfn "My total with 4 as initial state is:%A" (exec myNewCountWithTotalResult 4)
是的,我不确定自己是否理解这一点。
另外:忘了我提到的 "monad" ;-)
我是一名长期的 C# 开发人员,并试图掌握 F# 并为此我想做一个小项目,我需要以下内容:
是否可以创建具有以下行为的函数以及如何创建?注意:我知道 ref
可能可行,但我希望它更 "pure" 实用。
let count (x:int) (y:iny): (int -> int * int) =
??
let myCount = count 1
// --------
let myCount, value = myCount 2;; // value is now 3
let myCount, value = myCount 3;; // value is now 6
let myCount, value = myCount 1;; // value is now 7
您提供的 类型签名 不可能(因为您 return 一个包含两个整数的元组,但显然第一个应该再次具有相同的签名因为 count 1
本身是不可能的 - 你必须以某种方式包装它)。
但是根据你的例子,我认为你想要的应该是可能的:
这是一个与您的略有不同的版本,但我想您明白了:
type Counter = { value : int; update : int -> Counter }
let rec counter init =
{ value = init; update = fun upd -> counter (upd+init) }
这是实际操作:
> let myCounter = counter 1;;
val myCounter : Counter = {value = 1;
update = <fun:counter@118>;}
> let myCounter = myCounter.update 2;;
val myCounter : Counter = {value = 3;
update = <fun:counter@118>;}
> let myCounter = myCounter.update 3;;
val myCounter : Counter = {value = 6;
update = <fun:counter@118>;}
> let myCounter = myCounter.update 1;;
val myCounter : Counter = {value = 7;
update = <fun:counter@118>;}
对你来说够近了吗?
当然,如果你放弃纯粹,你可以让这种方式更简单(在 F# 中做这样的事情确实很常见):
let counter init =
let value = ref init
fun upd ->
value := !value + upd
!value
这是你的例子
> let myCounter = counter 1;;
val myCounter : (int -> int)
> myCounter 2;;
val it : int = 3
> myCounter 3;;
val it : int = 6
> myCounter 1;;
val it : int = 7
既然你提"pure functional"我就提"state monad"...
和 "update" 结合了更多:http://tomasp.net/blog/2014/update-monads/
做一些代码示例需要以下必要条件:将 fsharpx.extras 添加到为此代码制作的某个项目中。
#r @"..\packages\FSharpx.Extras.1.10.2\lib\FSharpx.Extras.dll"
open FSharpx.State
open System
let myCount value =
state {
let! s = getState
do! putState (s + value)
return s
}
let myNewCountWithTotalResult =
state {
let! _ = myCount 1
let! _ = myCount 2
let! _ = myCount 3
let! _ = myCount 1
return ()
}
printfn "My total with 0 as initial state is: %A" (exec myNewCountWithTotalResult 0)
//Just for the hell of it if you wanna initiate the state with something other than 0
//to get a totally different result
printfn "My total with 4 as initial state is:%A" (exec myNewCountWithTotalResult 4)
是的,我不确定自己是否理解这一点。
另外:忘了我提到的 "monad" ;-)