我的场景是用户输入要执行的文本的DSL。 text可以是数字操作,也可以是字符串或数字的关系操作(返回布尔值)。 在用户输入中,可以有常量值或变量(其中变量值必须从另一个源/字典获取并在操作中使用)
示例(数字操作)
fileActions.select()
关系操作示例
(1 + 2)
(@variableName@ + 2) //returns int
我有DU代表数字
(@countryname@ in {abc,def,ghi}) //returns bool over variable with string value
(3 > 5) //returns bool over int
(@VariableInt@ > 5) // bool over variable having int value
用于解释我的表达式/变量我有类似的东西,从这里得到variableName我想要返回字符串或int 所以我的RelationExpression | In可以得到字符串值
type NumberExpression
| VariableName of string //variable name
|Constant of int
| Add of NumberExpression * expression
type RelationExpression
| Boolean of bool
| GT of NumberExpression * NumberExpression
| In of NumberExpression * string list
对于变量的数字运算,对于relationexpression,因为它返回变量类型是int。现在我必须处理返回字符串值的变量的返回类型。 我的NumberExpression |变量如何返回int / string
我可以尝试创建一个float和string的鉴别器联合,我的函数将返回这个新的Discriminator联合,但现在问题是默认情况下浮点运算在我的新鉴别器联合上是无效的(即使它是浮点数值)。
let rec Interpret input =
match input with
| VariableName(name) ->
let stringvalue,datatype = datadictionary.[name] //assume value is from map. I need to do typecase and either return string or int here???
| Constant(value) ->value
虽然我的函数返回内部Float,但它的新联合类型并没有+运算符。因此使用DU返回任何一种类型的方法对我来说都不适用。如何处理?
答案 0 :(得分:4)
这是你可以做到的一种方式。我将首先显示代码,然后解释它:
type myResultType =
| Number of float
| StringItem of string
// I fleshed out your `myFunction` example so it actually compiles
let myFunction (input:string) =
match input.[input.Length-1] with
| 'F' -> input.[0..input.Length-2] |> float |> Number
| 'S' -> input.[0..input.Length-2] |> StringItem
// Use this one for unary operators (no examples given here)
let floatOp op result =
match result with
| Number n -> op n |> Number
| anythingElse -> anythingElse
// Use this one to define operators where the "real" float is the first operand
let floatOp2 op floatArg result =
match result with
| Number n -> op floatArg n |> Number
| anythingElse -> anythingElse
// Use this one to define operators where the "real" float is the second operand
let floatOp2' op result floatArg =
match result with
| Number n -> op n floatArg |> Number
| anythingElse -> anythingElse
let (+.) = floatOp2 (+)
let ( *. ) = floatOp2 (*) // Spaces needed so this doesn't look like a comment
// etc.
let (.+) = floatOp2' (+)
// etc.
let finalValue = (10.0) +. (myFunction "200F")
let finalValue' = (myFunction "200F") .+ 10.0
您无法重新定义现有的+
运算符,但可以创建自己的运算符,该运算符将在Number
个案例中运行(如果您的结果不执行任何操作type是StringItem
个案例。由于所有这些运算符的公共代码看起来几乎相同,因此我将其提取到自己的函数中。然后,您可以定义-.
,/.
等运算符,其方式与您定义+.
和*.
运算符的方式非常相似。
注意在定义*.
运算符时如何在括号内放置空格。只要您定义以*
字符开头(或结束)的自定义运算符,就必须这样做。否则,(*
或*)
看起来就像是评论的开头。例如,let (*!*) arg1 arg2 = ...
将F#解析器视为包含单个感叹号的注释,并且它认为您正在定义名为arg1
的函数,该函数采用名为arg2
的单个参数。但是,let ( *!* ) arg1 arg2 = ...
将被正确解析为定义带有两个参数的运算符*!*
。