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" ;-)