2016-10-10 5 views
2
내 계산 표현에 일부 사용자 지정 연산자를 정의 할

에서 사용자 정의 연산자를 정의하지만 member this.Map (f, s) ...member this.Map f s ...을 변경 Btw는계산 표현

type ZipSeq() = 

    [<CustomOperation("<*>")>] 
    member this.Apply f s = 
     f |> Seq.zip s |> Seq.map (fun (y, x) -> x(y)) 

    member this.Return x = 
     Seq.initInfinite (fun _ -> x) 

    // (a -> b) -> seq<a> -> seq<b> 
    [<CustomOperation("<!>")>] 
    member this.Map f s = 
     this.Apply (this.Return f) s 

let zipSeq = new ZipSeq() 

let f (a : float) = a * a 
let s = seq { yield 1. } 

// seq<b> 
let h1 = zipSeq.Map f s 

//thinking h1 should be the same as h2 
//but compilation error : ` This value is not a function and cannot be applied` 
let h2 = zipSeq { return f <!> s } 

를 작동 할 수 없습니다 어떻게 같은 오류를 제공합니다.

+1

나는 그것이 가능하지 않다고 생각합니다. 그래도 멋지다. – Tarmil

+0

당신은 계산 빌더의 일부가 아닌이 연산자들을 따로 따로 정의하여이 문법을 구현할 수 있어야하고, 그것들은'let!'-ed 또는'return! '일 수있는 모나드 인스턴스를 반환하게한다 - 에드. –

+0

다른 대안을 제안 해 주시겠습니까? – baio

답변

4

주석에서 이미 언급했듯이 계산식과 사용자 지정 연산자는 어떤 방식으로도 상호 작용하지 않는 두 개의 직교 언어 기능입니다. 사용자 정의 연산자를 사용하려면 사용자 정의 연산자를 정의하고 사용하면됩니다 (범위를 제한하는 유형의 멤버 또는 명시 적으로 열어야하는 모듈의 멤버로 정의 할 수 있음).

당신이 실용적 프로그래밍 스타일과 같은 뭔가를 계산 표현식을 사용하여에 관심이 있다면, 당신이 계산 표현식에서 "지퍼와 같은"작업을 정의 할 수 있음을 주목할 필요가있다.

zipSeq { 
    for x in [1; 2; 3] do 
    zip y in ['a'; 'b'; 'c'] 
    yield x, y } 

이것은 [1,a; 2,b; 3,c]와 시퀀스를 생성 : 이것은 당신이 좋은 구문을 압축하는 작성할 수 있습니다. 수 계산 빌더 정의는 다음과 같이 보입니다 수행

type SeqZipBuilder() = 
    member x.For(ev:seq<'T>, loop:('T -> #seq<'U>)) : seq<'U> = 
     Seq.collect loop ev 
    member x.Yield(v:'T) : seq<'T> = seq [v] 
    [<CustomOperation("zip",IsLikeZip=true)>] 
    member x.Zip 
     (outerSource:seq<'Outer>, innerSource:seq<'Inner>, 
     resultSelector:('Outer -> 'Inner -> 'Result)) : seq<'Result> = 
     Seq.map2 resultSelector outerSource innerSource 

let zipSeq = SeqZipBuilder() 

(지금까지 내가 아는 한,이 아주 잘 문서화 아니라, 보여 F# repo tests의 예제의 무리가 얼마나 지퍼 같은 (및 기타) 사용자 지정 작업을 정의 할 수 있습니다.