2009-06-24 18 views
7

Grałem z F # (Visual Studio 2010 beta 1) i napisałem mały skrypt konsoli, który poprosił użytkownika o wprowadzenie 2 liczb i operatora, a następnie go wykonał. Działa to dobrze, oprócz drobnych, ale denerwujących rzeczy: czasami moje instrukcje printfn są ignorowane. Umieściłem punkty przerwania w kodzie, aby zobaczyć, że tak jest rzeczywiście.F # dziwny problem printfn

Fragment kodu:

let convert (source : string) = 
    try System.Int32.Parse(source) 
    with :? System.FormatException -> 
     printfn "'%s' is not a number!" source; 
     waitForExitKey(); 
     exit 1 

let read = 
    printfn "Please enter a number."; 
    System.Console.ReadLine 

let num1 : int = read() |> convert // the printfn in the read function is run... 
let num2 : int = read() |> convert // ... but here is ignored 

To nie jest kompletnym źródłem oczywiście, ale myślę, że będzie wystarczająco. Jeśli potrzebujesz pełnego źródła, daj mi znać.

Moje pytanie jest bardzo proste: co powoduje ten problem z printfn? czy robię coś źle?

Dzięki z góry, ShdNx

Odpowiedz

15

This page ma częściowe wyjaśnienie tego, co się dzieje, ale wersja krótka i słodki, że F # będzie wykonaj dowolną wartość na deklaracji, jeśli nie przyjmuje parametrów.

let read = 
    printfn "Please enter a number." 
    System.Console.ReadLine 

Od read nie bierze żadnych parametrów, jego wykonywane natychmiast deklaracji i wiąże wartość zwracaną przez funkcję do identyfikatora read.

Nawiasem mówiąc, twoja wartość zwracana jest funkcją typu (unit -> string). Wynika to z faktu, że F # automatycznie curries functions, jeśli nie zostały przekazane wszystkie ich parametry. ReadLine oczekuje jednego parametru jednostki, ale ponieważ nie jest przekazywane, faktycznie wiąże się read z samą funkcją ReadLine.

Rozwiązanie jest w następujący sposób:

let read() = // read takes one unit parameter 
    printfn "Please enter a number." 
    System.Console.ReadLine() // pass paramter to ReadLine method 

Ponieważ read jeden parametr, jego ponownego oceniano każdorazowo Nazywa. Dodatkowo przekazujemy parametr do ReadLine, w przeciwnym razie po prostu zwrócony zostanie funkcja ReadLine.

+0

Dziękuję bardzo! Niestety Ray był szybszy, więc przyjąłem jego odpowiedź. Ale nadal cieszę się, że to wyjaśniłeś. Dzięki jeszcze raz! – ShdNx

+0

Zgadzam się! +1 dla lepszego wyjaśnienia! –

7

Rozumiem, że może to być mylące. W twoim przykładzie printfn działa wcześniej niż myślisz. Faktycznie wykona się nawet bez połączenia z numerem read(), tzn. Skomentuje ostatnie dwa wiersze i nadal będzie drukowany komunikat.

Myślę, że intencją jest coś takiego:

let read() = 
    printfn "Please enter a number."; 
    System.Console.ReadLine() 

Spowoduje to utworzenie funkcji „wielokrotnego użytku” zamiast wiązania funkcji do identyfikatora, jak w oryginalnym przykładem.

Jak sidenote, użycie tutaj średnikami jest opcjonalne, więc można po prostu napisać:

let read() = 
    printfn "Please enter a number." 
    System.Console.ReadLine() 
+0

Dziękuję bardzo, myślę, że rozumiem to teraz! Używam średników, ponieważ automatycznie dodajemy średnik po każdym wierszu i denerwuje mnie, jeśli nie widzę żadnego ... :-) – ShdNx

Powiązane problemy