F# 可变到不可变
天哪,
我最近一直在涉足一些 F#,并想出了以下从一些 C# 代码移植来的字符串生成器。 如果它传递属性中定义的正则表达式,它将对象转换为字符串。 对于手头的任务来说,这可能有点过分了,但出于学习目的。
目前,BuildString 成员使用可变字符串变量updatedTemplate。 我一直在绞尽脑汁想找到一种没有任何可变对象的方法来做到这一点,但没有成功。 这让我想到了我的问题。
是否可以在没有任何可变对象的情况下实现 BuildString 成员函数?
干杯,
迈克尔
//The Validation Attribute
type public InputRegexAttribute public (format : string) as this =
inherit Attribute()
member self.Format with get() = format
//The class definition
type public Foo public (firstName, familyName) as this =
[<InputRegex("^[a-zA-Z\s]+$")>]
member self.FirstName with get() = firstName
[<InputRegex("^[a-zA-Z\s]+$")>]
member self.FamilyName with get() = familyName
module ObjectExtensions =
type System.Object with
member this.BuildString template =
let mutable updatedTemplate : string = template
for prop in this.GetType().GetProperties() do
for attribute in prop.GetCustomAttributes(typeof<InputRegexAttribute>,true).Cast<InputRegexAttribute>() do
let regex = new Regex(attribute.Format)
let value = prop.GetValue(this, null).ToString()
if regex.IsMatch(value) then
updatedTemplate <- updatedTemplate.Replace("{" + prop.Name + "}", value)
else
raise (new Exception "Regex Failed")
updatedTemplate
open ObjectExtensions
try
let foo = new Foo("Jane", "Doe")
let out = foo.BuildInputString("Hello {FirstName} {FamilyName}! How Are you?")
printf "%s" out
with | e -> printf "%s" e.Message
Gday All,
I have been dabbling in some F# of late and I came up with the following string builder that I ported from some C# code. It converts an object into a string provided it passes a Regex defined in the attributes. Its probably overkill for the task at hand but its for learning purposes.
Currently the BuildString member uses a mutable string variable updatedTemplate. I have been racking my brain to work out a way doing this without any mutable objects to no avail. Which brings me to my question.
Is it possible to implement the BuildString member function without any mutable objects?
Cheers,
Michael
//The Validation Attribute
type public InputRegexAttribute public (format : string) as this =
inherit Attribute()
member self.Format with get() = format
//The class definition
type public Foo public (firstName, familyName) as this =
[<InputRegex("^[a-zA-Z\s]+$")>]
member self.FirstName with get() = firstName
[<InputRegex("^[a-zA-Z\s]+$")>]
member self.FamilyName with get() = familyName
module ObjectExtensions =
type System.Object with
member this.BuildString template =
let mutable updatedTemplate : string = template
for prop in this.GetType().GetProperties() do
for attribute in prop.GetCustomAttributes(typeof<InputRegexAttribute>,true).Cast<InputRegexAttribute>() do
let regex = new Regex(attribute.Format)
let value = prop.GetValue(this, null).ToString()
if regex.IsMatch(value) then
updatedTemplate <- updatedTemplate.Replace("{" + prop.Name + "}", value)
else
raise (new Exception "Regex Failed")
updatedTemplate
open ObjectExtensions
try
let foo = new Foo("Jane", "Doe")
let out = foo.BuildInputString("Hello {FirstName} {FamilyName}! How Are you?")
printf "%s" out
with | e -> printf "%s" e.Message
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我认为你总是可以将“仅具有一种效果(改变局部变量)的序列上的 for 循环”转换为摆脱可变的代码; 这是一般变换的示例:
您的特定示例具有嵌套循环,因此这是一个分两步显示相同类型机械变换的示例:(
在上面的代码中,我使用名称“x2”和“x3”来制作范围更明显,但您可以在整个过程中使用名称“x”。)
尝试对示例代码进行相同的转换并发布您自己的答案可能是值得的。 这不一定会产生最惯用的代码,但可以作为将 for 循环转换为 Seq.fold 调用的练习。
(也就是说,在这个例子中,整个目标主要是一个学术练习——带有可变的代码是“很好”。)
I think you can always transform a "for loop over a sequence with only one effect (mutating a local variable)" into code that gets rid of the mutable; here's an example of the general transform:
Your particular example has nested loops, so here's an example of showing the same kind of mechanical transform in two steps:
(In the code above, I used the names 'x2' and 'x3' to make scoping more apparent, but you can just use the name 'x' throughout.)
It may be worthwhile to try to do this same transform on your example code and post your own answer. This won't necessarily yield the most idiomatic code, but can be an exercise in transforming a for loop into a Seq.fold call.
(That said, in this example the whole goal is mostly an academic exercise - the code with the mutable is 'fine'.)
我没有时间将其写成代码,但是:
seq.map_concat
将GetProperties()
返回的属性数组转换为(属性、属性)元组序列。那有意义吗?
I don't have the time to write this up as code, but:
seq.map_concat
to go from the array of properties returned byGetProperties()
to a sequence of (property, attribute) tuples.seq.fold
with the previous two bits to do the whole transformation, using the original template as the initial value for the aggregation. The overall result will be the final replaced string.Does that make sense?
纯粹的函数式方法:
A purely functional approach: