F# 重写简单C#嵌套类

F# 重写简单C#嵌套类,f#,F#,在F#中实现这个嵌套类功能的优雅方式是什么 这是我的第一次尝试,但感觉应该有一个性感的一行: let aliases = (Seq.initInfinite (sprintf "t%d")).GetEnumerator() let getNextAlias() = aliases.MoveNext() |> ignore aliases.Current 这是快速而肮脏的翻译 type Aliaser () = let mutable _count = 0 me

在F#中实现这个嵌套类功能的优雅方式是什么

这是我的第一次尝试,但感觉应该有一个性感的一行:

let aliases = (Seq.initInfinite (sprintf "t%d")).GetEnumerator()

let getNextAlias() = 
    aliases.MoveNext() |> ignore
    aliases.Current

这是快速而肮脏的翻译

type Aliaser () =
  let mutable _count = 0
  member x.GetNextAlias() = 
    let value = _count.ToString()
    _count <- _count + 1
    "t" + value
这是一个声明,它将使用值和要执行的函数调用函数
callWithValue
,并使用下一个值重复

下面是一个使用它的示例

let main () =
    let inner value (next : unit -> unit )=  
        printfn "Value: %s" value
        let input = System.Console.ReadLine()
        if input <> "quit" then next()
    createAliaser inner     

main()
let main()=
让内部值(下一步:单位->单位)=
printfn“值:%s”值
让输入=System.Console.ReadLine()
如果输入“退出”,则下一步()
createAliaser内部
main()

通常的编写方法是创建一个函数,在闭包中捕获局部状态:

let getNextAlias = 
  let count = ref 0
  (fun () -> 
     count := !count + 1; 
     sprintf "t%d" (!count))
getNextAlias
的类型只是
unit->string
,当您重复调用它时,它返回字符串“t1”、“t2”。。。这依赖于可变状态,但可变状态对用户是隐藏的

关于是否可以在没有可变状态的情况下执行此操作,简单的答案是否定的,因为当您使用相同的参数调用纯函数函数两次时,它必须返回相同的结果。因此,您必须使用以下结构编写一些内容:

let alias, state1 = getNextAlias state0
printf "first alias %s" alias
let alias, state2 = getNextAlias state1
printf "second alias %s" alias
// ...
正如您所看到的,您需要保留一些状态并在整个代码中维护它。在F#中,处理这个问题的标准方法是使用可变状态。在Haskell中,您可以使用State monad,它允许您隐藏状态的传递。使用该实现,您可以编写如下内容:

let getNextAlias = state { 
  let! n = getState
  do! setState (n + 1)
  return sprintf "t%d" n }

let program =
  state { 
    let! alias1 = getNextAlias()
    let! alias2 = getNextAlias() 
    // ...
  }

execute progam 0 // execute with initial state

这与其他计算非常相似,例如
lazy
seq
,实际上,
状态{..}
块中的计算有一些状态,您可以通过提供状态的初始值来执行它们。但是,除非您有充分的理由需要纯功能性解决方案,否则我更喜欢实用F#编程的第一个版本。

我会使用
Seq.unfold:(('a->('b*'a)选项)->'a->seq谢谢,但我希望功能简洁。现在这很酷。我仍然没有克服CPS的难以捉摸性。@Daniel,CPS有时仍然让我头晕目眩。这很有帮助。你有没有找到不声明可变状态的方法?我可以补充一点:你可以使用
递增计数
而不是
计数:=!count+1
我意识到在某个地方必须存在可变状态,但我喜欢将其隐藏在预定义的模式中(例如,lazy,seq)。@Daniel:在最新更新中添加了使用状态monad的解决方案:-)。除非实现类似于我最初发布的内容,否则不会在调用之间保持状态。是的,但我会使用生成的序列作为状态。
let alias, state1 = getNextAlias state0
printf "first alias %s" alias
let alias, state2 = getNextAlias state1
printf "second alias %s" alias
// ...
let getNextAlias = state { 
  let! n = getState
  do! setState (n + 1)
  return sprintf "t%d" n }

let program =
  state { 
    let! alias1 = getNextAlias()
    let! alias2 = getNextAlias() 
    // ...
  }

execute progam 0 // execute with initial state
let alias = 
    Seq.unfold (fun count -> Some(sprintf "t%i" count, count+1)) 0