2009-06-24 22 views
7

Estaba jugando con F # (Visual Studio 2010 beta 1), y escribí un pequeño script de consola que pedía al usuario ingresar 2 números y un operador y luego lo ejecutaba. Funciona bien, aparte de una cosa pequeña, pero molesta: a veces mis instrucciones printfn son ignoradas. Coloqué puntos de interrupción en el código para ver que ese es realmente el caso.F # strange printfn problem

El fragmento de código:

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 

Esta no es la fuente completa, por supuesto, pero creo que va a ser suficiente. Si necesitas la fuente completa solo házmelo saber.

Así que mi pregunta es bastante simple: ¿qué causa este problema con printfn? ¿Estoy haciendo algo mal?

Gracias de antemano, ShdNx

Respuesta

15

This page tiene una explicación parcial de lo que está pasando, pero la versión corta y dulce es que F # voluntad ejecuta cualquier valor en la declaración si no toma los parámetros.

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

Desde read no toma ningún parámetro, su ejecutadas inmediatamente después de la declaración y se une el valor de retorno de la función con el identificador read.

Por cierto, su valor de retorno pasa a ser una función con el tipo (unit -> string). Esto se debe a que F # automáticamente curries functions si no se pasan todos sus parámetros. ReadLine espera un parámetro de unidad, pero como no se transfiere, realmente vincula read a la función ReadLine.

La solución es la siguiente:

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

Desde read toma un parámetro, su re-evaluado cada vez que su llamada. Además, estamos pasando un parámetro al ReadLine; de lo contrario, devolveremos la función ReadLine como valor.

+0

¡Muchas gracias! Desafortunadamente, Ray fue más rápido, así que acepté su respuesta. Pero todavía estoy muy contento de que hayas aclarado esto. ¡Gracias de nuevo! – ShdNx

+0

¡Estoy de acuerdo! +1 para una explicación más clara! –

7

entiendo que esto puede ser confuso. En su ejemplo, printfn se ejecuta antes de lo que cree. En realidad, se ejecutará incluso sin llamar a read(), es decir, comentar las últimas dos líneas y todavía verá un mensaje impreso.

Creo que su intención es algo como esto:

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

Esto creará una función de "reutilizable" en lugar de fijarse en función de un identificador como en el ejemplo inicial.

Como anotación al margen, el uso del punto y coma aquí es opcional por lo que sólo puede escribir:

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

Muchas gracias, creo que lo entiendo ahora! Utilizo punto y coma porque automáticamente agrego un punto y coma después de cada línea y me molesta si no puedo ver ninguna ... :-) – ShdNx