문제

gday 모두,

나는 늦게 f#에 덤벼 들었고 일부 c# 코드에서 포팅 한 다음 문자열 빌더를 생각해 냈습니다. 객체를 문자열로 변환하여 속성에 정의 된 정규식을 통과하면 객체를 문자열로 변환합니다. 당면한 과제에 대한 과잉이지만 학습 목적을위한 것일 것입니다.

현재 BuildString 멤버는 변이 가능한 문자열 변수 업데이트 테템 플레이트를 사용합니다. 나는 돌연변이 가능한 물건없이 아무 소용이 없으면이 작업을 수행하기 위해 뇌를 쌓아 왔습니다. 내 질문에 나를 데려옵니다.

변이 가능한 객체없이 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
도움이 되었습니까?

해결책

나는 당신이 항상 "하나의 효과 (로컬 변수를 돌연변이하는) 단지 시퀀스를 통한 루프를 위해 A"를 변환 할 수 있다고 생각합니다. 일반적인 변환의 예는 다음과 같습니다.

let inputSeq = [1;2;3]

// original mutable
let mutable x = ""
for n in inputSeq do
    let nStr = n.ToString()
    x <- x + nStr
printfn "result: '%s'" x

// immutable
let result = 
    inputSeq |> Seq.fold (fun x n ->
        // the 'loop' body, which returns
        // a new value rather than updating a mutable
        let nStr = n.ToString()
        x + nStr
    ) ""  // the initial value
printfn "result: '%s'" result

특정 예제는 루프 중첩이 있으므로 다음은 두 단계로 동일한 종류의 기계적 변환을 보여주는 예입니다.

let inputSeq1 = [1;2;3]
let inputSeq2 = ["A";"B"]

let Original() = 
    let mutable x = ""
    for n in inputSeq1 do
        for s in inputSeq2 do
            let nStr = n.ToString()
            x <- x + nStr + s
    printfn "result: '%s'" x

let FirstTransformInnerLoopToFold() = 
    let mutable x = ""
    for n in inputSeq1 do
        x <- inputSeq2 |> Seq.fold (fun x2 s ->
            let nStr = n.ToString()
            x2 + nStr + s
        ) x
    printfn "result: '%s'" x

let NextTransformOuterLoopToFold() = 
    let result = 
        inputSeq1 |> Seq.fold (fun x3 n ->
            inputSeq2 |> Seq.fold (fun x2 s ->
                let nStr = n.ToString()
                x2 + nStr + s
            ) x3
        ) ""
    printfn "result: '%s'" result

(위의 코드에서 나는 'x2'와 'x3'이라는 이름을 사용하여 스코핑을보다 명백하게 만들었지 만 'x'라는 이름 만 사용할 수 있습니다.)

예제 코드에서 동일한 변환을 수행하고 자신의 답변을 게시하는 것이 좋습니다. 이것은 반드시 가장 관용 코드를 생성하는 것은 아니지만 루프를 seq.fold 호출로 변환하는 데 연습 할 수 있습니다.

(즉,이 예에서 전체 목표는 대부분 학문적 운동입니다.

다른 팁

나는 이것을 코드로 작성할 시간이 없지만 :

  • 가장 안쪽 부분을 나타내는 함수를 작성하고 문자열 (지금까지 결과)과 속성과 속성의 튜플을 가져 와서 교체 후 문자열을 반환합니다.
  • 사용 seq.map_concat 반환 된 속성 배열에서 이동합니다 GetProperties() (속성, 속성) 튜플의 시퀀스로.
  • 사용 seq.fold 이전의 두 비트가 전체 변환을 수행하여 원래 템플릿을 집계의 초기 값으로 사용합니다. 전반적인 결과는 최종 대체 문자열입니다.

말이 돼?

순전히 기능적 접근 :

module ObjectExtensions =
type System.Object with
    member this.BuildString template =
        let properties = Array.to_list (this.GetType().GetProperties())
        let rec updateFromProperties (pps : Reflection.PropertyInfo list) template =
            if pps = List.Empty then
                template
            else 
                let property = List.hd pps
                let attributes = Array.to_list (property.GetCustomAttributes(typeof<InputRegexAttribute>,true))
                let rec updateFromAttributes (ats : obj list) (prop : Reflection.PropertyInfo) (template : string) =
                    if ats = List.Empty then
                        template
                    else
                        let a = (List.hd ats) :?> InputRegexAttribute
                        let regex = new Regex(a.Format)
                        let value = prop.GetValue(this, null).ToString()
                        if regex.IsMatch(value) then
                            template.Replace("{" + prop.Name + "}", value)
                        else
                            raise (new Exception "Regex Failed\n")
                updateFromProperties(List.tl pps) (updateFromAttributes attributes property template)
        updateFromProperties properties template
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top