2013-01-19 15 views
7

mam przeliczania niektórych F # kod do SML i widzę wiele zastosowań tego operatora rurociągu <|, na przykład:Konwersja operatorzy # rurociągów F (<|, >>, <<), aby SML

let printPeg expr = 
    printfn "%s" <| pegToString expr 

<| operator jest zdefiniowany jako tylko pozornie:

# let (<|) a b = a b ;; 
val (<|) : ('a -> 'b) -> 'a -> 'b = <fun> 

Zastanawiam się, dlaczego przeszkadza zdefiniować i użyć tego operatora w F #, to jest po prostu, aby mogli unikać umieszczania w parens jak to ?:

let printPeg expr = 
    Printf.printf "%s" (pegToString expr) 

O ile mogę powiedzieć, to byłaby konwersja powyższego kodu F # na OCaml, prawda?

Ponadto, w jaki sposób mogę zaimplementować operatory F # z << i >> w Ocaml?

(operator |> wydaje się być po prostu: let (|>) a b = b a ;;)

+0

Po prostu z ciekawości spędzam dużo czasu tłumacząc z OCaml na F # z powodu dużych zbiorów otwartego kodu w OCaml, łatwość tłumaczenia na F #, możliwość korzystania z Visual Studio i wsparcie tutaj, jakie korzyści zyskujesz przechodząc od F # do OCaml? –

+0

@GuyCoder: Po pierwsze, nie jestem w systemie Windows. Pracuję w systemie Linux. Przypuszczam, że mógłbym użyć Mono do rozwijania F # na Linuksie, ale bardziej jestem zaznajomiony z OCaml i jego łańcuchem narzędzi i myślę, że nie chcę polegać na środowisku wykonawczym Mono. Podobają mi się również niektóre funkcje, które OCaml ma, że ​​F # brakuje jak funktory i moduły pierwszej klasy. Tak, zauważyłem, że jest dużo informacji o przechodzeniu z OCaml do F #, ale nie tak bardzo idąc w drugą stronę. Potrzebujemy jakiejś biblioteki/warstwy kompatybilności. – aneccodeal

+0

Czy wiesz o [FSharp.PowerPack.Compatibility.dll] (https://github.com/fsharp/powerpack/tree/master/src/FSharp.PowerPack.Compatibility)? Nie obejmuje wszystkiego, ale pomaga. Obecnie tłumaczę kod ML z funktorami, będąc po raz pierwszy z funktorami, widzę apel i naprawdę uwielbiam podróż w czasie (http://caml.inria.fr/pub/docs/manual-ocaml- 4.00/manual030.html) funkcja debugowania OCaml. OCaml ma wiele do zaoferowania, a ja polecałbym go równie często jak F #. :) –

Odpowiedz

11

Bezpośrednio z F# source:

let inline (|>) x f = f x 
let inline (||>) (x1,x2) f = f x1 x2 
let inline (|||>) (x1,x2,x3) f = f x1 x2 x3 
let inline (<|) f x = f x 
let inline (<||) f (x1,x2) = f x1 x2 
let inline (<|||) f (x1,x2,x3) = f x1 x2 x3 
let inline (>>) f g x = g(f x) 
let inline (<<) f g x = f(g x) 
14

dlatego starał się zdefiniować i użyć tego operatora w F #, to tylko dlatego można uniknąć wprowadzania parens?

To dlatego, że funkcjonalny sposób programowania zakłada gwintowanie wartości przez łańcuch funkcji. Porównaj:

let f1 str server = 
    str 
    |> parseUserName 
    |> getUserByName server 
    |> validateLogin <| DateTime.Now 

let f2 str server = 
    validateLogin(getUserByName(server, (parseUserName str)), DateTime.Now) 

W pierwszym ujęciu wyraźnie widzimy wszystko, co dzieje się z wartością. Czytając drugi, musimy przejść przez wszystkie pareny, aby dowiedzieć się, co się dzieje.

This article o składzie funkcji wydaje się być istotne.

Tak, tak w zwykłym życiu chodzi głównie o pareny. Ale także operatorzy rurociągów są ściśle powiązani z aplikacją funkcji cząstkowych i bez-punktowym stylem kodowania. Zobacz np. Programming is "Pointless".

Rurociąg |> i funkcja skład >><< operatorzy mogą produkować kolejny ciekawy efekt, gdy są one przekazywane do funkcji wyższego poziomu, jak here.

+0

-1 "ponieważ funkcjonalny sposób programowania zakłada gwintowanie wartości przez łańcuch funkcji". Jeśli to prawda, to OCaml miałby takie operatory przed F #. Twoje przykłady również nie są równoważne, ponieważ nie powiodło Ci się i dodano niepotrzebne nawiasy. 'validateLogin DateTime.Now (getUserByName server (parseUserName str))'. –

+5

@JonHarrop Prosimy uważnie przeczytać. Celowo wprowadziłem parametr 'date' a ** second **, aby zademonstrować użyteczność operatora' <| '. – bytebuster

9

Baterie OCaml obsługuje tych operatorów, ale ze względu na pierwszeństwo, asocjatywność i inne dziwactwa składniowe (jak Camlp4) używa różnych symboli. Które z używanych symboli zostało niedawno ustalone, są pewne zmiany. Patrz: Batteries API:

val (|>) : 'a -> ('a -> 'b) -> 'b 

Zastosowanie funkcji. x |> f jest równoważne f x.

val (**>) : ('a -> 'b) -> 'a -> 'b 

Zastosowanie funkcji. f **> x jest równoważne f x. Uwaga Nazwa tego operatora nie jest zapisana w kamieniu. Wkrótce się to zmieni.

val (|-) : ('a -> 'b) -> ('b -> 'c) -> 'a -> 'c 

Skład funkcji. f | - g jest zabawne x -> g (f x). Jest to równoznaczne z dwukrotnym zastosowaniem < **.

val (-|) : ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b 

Skład funkcji. f - | g jest zabawne x -> f (g x). Matematycznie jest to operator o.

Ale Batteries trunk zapewnia: stosowanie

val (@@) : ('a -> 'b) -> 'a -> 'b 

Function. [f @@ x] jest równoważne [f x].

val (%) : ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b 

Skład funkcji: operator matematyczny [o].

val (|>) : 'a -> ('a -> 'b) -> 'b 

Aplikacja "rura": funkcja. [x |> f] jest równoważne [f x].

val (%>) : ('a -> 'b) -> ('b -> 'c) -> 'a -> 'c 

Skład funkcji rurociągów. [f%> g] to [zabawa x -> g (fx)].

+0

+1 za notowanie Battries. –

+0

Dobrze o tym wiedzieć, podobnie jak "<|" powodować problemy dla camlp4? – aneccodeal

+0

Nie, myślę, że tylko '<<' and '>>' do, jeśli używasz ofert. – lukstafi

6

Zastanawiam się, dlaczego zawracają sobie głowy definiowaniem i używaniem tego operatora w F #, czy to jest tak, aby mogli uniknąć umieszczania parensów w ten sposób?

Doskonałe pytanie. Określony operator, do którego się odwołujesz (<|) jest dość bezużytecznym edytorem IME. Pozwala na unikanie nawiasów przy rzadkich okazjach, ale generalnie komplikuje składnię, przeciągając więcej operatorów i sprawia, że ​​trudniej jest dla mniej doświadczonych programistów F # (których jest teraz wielu), aby zrozumieć twój kod. Więc przestałem go używać.

Operator |> jest o wiele bardziej przydatny, ale tylko dlatego, że pomaga F # poprawnie wnioskować o typach w sytuacjach, w których OCaml nie miałby problemu. Na przykład, oto niektóre OCaml:

List.map (fun o -> o#foo) os 

Bezpośrednią odpowiednik nie w F #, ponieważ typ o nie można wnioskować przed odczytaniem jej foo własność więc idiomatyczne rozwiązaniem jest przepisać kod tak użyciu |> tak F # można wywnioskować typ o przed foo służy:

os |> List.map (fun o -> o.foo) 

rzadko używać innych operatorów (<< i >>), ponieważ również skomplikować składnię. Nie lubię też bibliotek kombinatorycznych parserów, które przyciągają wielu operatorów.

Przykład Bytebuster dało to ciekawy:

let f1 str server = 
    str 
    |> parseUserName 
    |> getUserByName server 
    |> validateLogin <| DateTime.Now 

chciałbym napisać to jako:

let f2 str server = 
    let userName = parseUserName str 
    let user = getUserByName server userName 
    validateLogin user DateTime.Now 

Brak wsporniki w moim kodu. Moje tymczasowe mają nazwy, więc pojawiają się w debugerze i mogę je sprawdzić, a Intellisense może dać mi zwrot w stylu, gdy najecham na nie myszą.Te cechy są cenne dla kodu produkcyjnego, który będą utrzymywać niefachowcy F #.

+1

-1: Odpowiadasz na pytania, które nie zostały zadane. Nie chodzi tu o osobiste preferencje ani o to, czy operatorzy potoku i kompozycji są przydatni. Nie chodzi również o zastąpienie '|>' serią instrukcji "let", tak jak podczas przeglądania mojej odpowiedzi. Twoja uwaga na temat wnioskowania o typ wydaje się jednak ważna, więc jeśli rozważysz czyszczenie swojej odpowiedzi, będzie to wyglądało bardziej konstruktywnie. – bytebuster

+5

+1 Proszę podać dodatkowe informacje w odpowiedziach. Wiele razy zadaję pytanie, ponieważ muszę coś wiedzieć, a to, o co pytam, nie jest tym, czego potrzebuję, ponieważ nie wiem dokładnie, czego potrzebuję. Gdybym to zrobił, nie zadawałbym tylu pytań. Przydatności |> z wnioskiem o typ zajęło mi trochę czasu, aby zrozumieć, a John zauważa to tutaj za darmo. Czytelnicy mogą to zignorować. Nie jest to sprzeczne z biuletynem :) ale muszę powiedzieć, że nadal mam problem z etosem SO. Czy to jest widok dawania ryb lub uczenia ludzi łowienia ryb? –

Powiązane problemy