gpt4 book ai didi

F# 计算表达式的用法

转载 作者:行者123 更新时间:2023-12-01 17:54:12 25 4
gpt4 key购买 nike

我是一名学生,想学习F#和函数式编程逻辑,但我对计算表达式有疑问。我认为我无法理解计算表达式的逻辑,因为我无法解决这个问题,并且我没有看到在这个问题中使用计算表达式有任何有用的东西。我认为这是一种重写 F# 的几个基本功能并以我们自己的方式实现的方法,但在这个问题中我看不到要点。感谢您抽出宝贵的时间,很抱歉提出了很长的问题。

A function from a type 'env to a type 'a can be seen as a computation that
computes a value of type 'a based on an environment of type 'env. We call such
a computation a reader computation, since compared to ordinary computations,
it can read the given environment. Below you find the following:

• the definition of a builder that lets you express reader computations
using computation expressions

• the definition of a reader computation ask : 'env -> 'env that returns the
environment

• the definition of a function runReader : ('env -> 'a) -> 'env -> 'a that
runs a reader computation on a given environment

• the definition of a type Expr of arithmetic expressions

Implement a function eval : Expr -> Map<string, int> -> int that evaluates
an expression using an environment which maps identifiers to values.

NB! Use computation expressions for reader computations in your implementation.

Note that partially applying eval to just an expression will yield a function of
type map <string, int> -> int, which can be considered a reader computation.
This observation is the key to using computation expressions.

The expressions are a simplified subset based on
Section 18.2.1 of the F# 4.1 specification:
https://fsharp.org/specs/language-spec/4.1/FSharpSpec-4.1-latest.pdf

*)

type ReaderBuilder () =
member this.Bind (reader, f) = fun env -> f (reader env) env
member this.Return x = fun _ -> x

let reader = new ReaderBuilder ()

let ask = id

let runReader = (<|)

type Expr =
| Const of int // constant
| Ident of string // identifier
| Neg of Expr // unary negation, e.g. -1
| Sum of Expr * Expr // sum
| Diff of Expr * Expr // difference
| Prod of Expr * Expr // product
| Div of Expr * Expr // division
| DivRem of Expr * Expr // division remainder as in 1 % 2 = 1
| Let of string * Expr * Expr // let expression, the string is the identifier.


let eval (e:Expr) : (Map<string, int> -> int) = failwith "not yet implemented"

// //Example:
// //keeping in mind the expression: let a = 5 in (a + 1) * 6
// let expr = Let ("a",Const 5, Prod(Sum(Ident("a"),Const 1),Const 6))
// eval expr Map.empty<string,int>
// should return 36
`

最佳答案

读取器计算表达式将允许您通过多个计算隐式地对环境进行线程化。例如,您可能有类似的内容:

let rec eval e : Map<string,int> -> int =
reader {
match e with
...
| Add(e1, e2) ->
let! i1 = eval e1 // implicitly thread environment through
let! i2 = eval e2 // same here
return i1 + i2
...
}

尽管eval的完整签名是Expr -> Map<string,int> -> int ,当我们使用let!时在计算表达式中我们只需要传递 Expr中,我们可以将结果绑定(bind)到 int无需显式传递 map 。

请注意,对于 IdentLet在这种情况下,您实际上需要显式处理映射来查找或设置标识符的值 - 但您可以使用 let! m = ask将 map 从环境中拉出。

当然完全有可能编写 eval 的实现不使用 reader表达式,但您可能会发现在任何地方对环境进行线程化只会给代码增加乏味的噪音,使其更难以理解。

关于F# 计算表达式的用法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53659986/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com