Pregunta

Alguien tiene un decente ejemplo, preferiblemente prácticos y útiles, se podría publicar lo que demuestra el concepto?

¿Fue útil?

Solución

(Edición:un pequeño Ocaml FP Koan para empezar las cosas)

El Koan de la Alarmada (Un koan acerca de la comida, que no es acerca de la comida)

Un estudiante se acercó a Jacques de las Garrigas y dijo, "no entiendo lo que alarmada es bueno." Jacques respondió, "dime cuál es tu comida favorita y tu postre favorito".El desconcertado estudiante respondió que le gustaba okonomiyaki y kanten, pero mientras que su restaurante favorito servido de gran okonomiyaki, sus kanten siempre le dio un dolor de estómago a la mañana siguiente.Para Jacques tomó el estudiante a comer a un restaurante que sirve okonomiyaki tan buena como la del estudiante de los favoritos, luego lo llevó a través de la ciudad a una tienda en la que hizo un excelente kanten donde el estudiante felizmente aplicado el resto de su apetito.El estudiante fue saciada, pero él no estaba iluminado ...hasta la mañana siguiente cuando se despertó y su estómago se sentía bien.

Mis ejemplos cubrirá usando para la reutilización y la encapsulación de código.Esto es bastante obvio una vez que se mire estos y debe darle una hormigón simple ejemplo que se puede pensar en aplicar en numerosas situaciones.

Queremos hacer un mapa encima de un árbol.Esta función podría ser al curry y se aplican a cada nodo, si se necesita más de un argumento, ya que estaríamos aplicando el uno en el nodo como es el argumento final.No tiene que ser al curry, pero la escritura otro función (suponiendo que esta función se utiliza en otros casos con otras variables) sería un desperdicio.

type 'a tree = E of 'a | N of 'a * 'a tree * 'a tree
let rec tree_map f tree = match tree with
    | N(x,left,right) -> N(f x, tree_map f left, tree_map f right)
    | E(x) -> E(f x)

let sample_tree = N(1,E(3),E(4)
let multiply x y = x * y
let sample_tree2 = tree_map (multiply 3) sample_tree

pero este es el mismo como:

let sample_tree2 = tree_map (fun x -> x * 3) sample_tree

Para este caso sencillo, no es convincente.Lo que realmente es, sin embargo, y potente una vez que utilice el lenguaje más y, naturalmente, vienen a través de estas situaciones.El otro ejemplo, con algunos reutilización de código como alarmada.Un la recurrencia de la relación para crear números primos.Montón de similitud en lo que hay:

let rec f_recurrence f a seed n =
    match n with
    | a -> seed
    | _ -> let prev = f_recurrence f a seed (n-1) in
           prev + (f n prev)

let rowland = f_recurrence gcd 1 7
let cloitre = f_recurrence lcm 1 1

let rowland_prime n = (rowland (n+1)) - (rowland n)
let cloitre_prime n = ((cloitre (n+1))/(cloitre n)) - 1

Ok, ahora rowland y cloitre están al curry funciones, ya que tiene variables libres, y podemos obtener un índice de la secuencia sin saber o preocuparse por f_recurrence.

Otros consejos

Mientras que los ejemplos anteriores contestó a la pregunta, aquí son dos simples ejemplos de cómo Alarmada puede ser beneficioso para F# programación.

open System.IO

let appendFile (fileName : string) (text : string) =
    let file = new StreamWriter(fileName, true)
    file.WriteLine(text)
    file.Close()

// Call it normally    
appendFile @"D:\Log.txt" "Processing Event X..."

// If you curry the function, you don't need to keep specifying the
// log file name.
let curriedAppendFile = appendFile @"D:\Log.txt"

// Adds data to "Log.txt"
curriedAppendFile "Processing Event Y..."

Y no olvides que puedes curry el Printf de la familia de función!En el curry versión, aviso de la clara falta de una expresión lambda.

// Non curried, Prints 1 2 3 
List.iter (fun i -> printf "%d " i) [1 .. 3];;

// Curried, Prints 1 2 3
List.iter (printfn "%d ") [1 .. 3];;

Alarmada se describe el proceso de transformación de una función con varios argumentos en una cadena de un solo argumento funciones.Ejemplo en C#, por un período de tres argumento de la función:

Func<T1, Func<T2, Func<T3, T4>>> Curry<T1, T2, T3, T4>(Func<T1, T2, T3, T4> f)
{
    return a => b => c => f(a, b, c);
}

void UseACurriedFunction()
{
    var curryCompare = Curry<string, string, bool, int>(String.Compare);
    var a = "SomeString";
    var b = "SOMESTRING";
    Console.WriteLine(String.Compare(a, b, true));
    Console.WriteLine(curryCompare(a)(b)(true));

    //partial application
    var compareAWithB = curryCompare(a)(b);
    Console.WriteLine(compareAWithB(true));
    Console.WriteLine(compareAWithB(false));
}

Ahora, el argumento booleano es probablemente no el argumento de que había más probable es que desee dejar de abrir con una aplicación parcial.Esta es una razón por la que el orden de los argumentos en F# funciones puede parecer un poco extraño al principio.Vamos a definir una diferente C# curry función:

Func<T3, Func<T2, Func<T1, T4>>> BackwardsCurry<T1, T2, T3, T4>(Func<T1, T2, T3, T4> f)
{
    return a => b => c => f(c, b, a);
}

Ahora, podemos hacer algo un poco más útil:

void UseADifferentlyCurriedFunction()
{
    var curryCompare = BackwardsCurry<string, string, bool, int>(String.Compare);

    var caseSensitiveCompare = curryCompare(false);
    var caseInsensitiveCompare = curryCompare(true);

    var format = Curry<string, string, string, string>(String.Format)("Results of comparing {0} with {1}:");

    var strings = new[] {"Hello", "HELLO", "Greetings", "GREETINGS"};

    foreach (var s in strings)
    {
        var caseSensitiveCompareWithS = caseSensitiveCompare(s);
        var caseInsensitiveCompareWithS = caseInsensitiveCompare(s);
        var formatWithS = format(s);

        foreach (var t in strings)
        {
            Console.WriteLine(formatWithS(t));
            Console.WriteLine(caseSensitiveCompareWithS(t));
            Console.WriteLine(caseInsensitiveCompareWithS(t));
        }
    }
}

¿Por qué son estos ejemplos en C#?Porque en F#, las declaraciones de función están al curry por defecto.Usted no necesita generalmente de curry funciones;ya están al curry.La principal excepción es la de los métodos de marco y otras funciones sobrecargadas, que tomar una tupla que contiene sus múltiples argumentos.Por lo tanto, usted podría querer curry tales funciones, y, de hecho, me encontré con esta pregunta cuando yo estaba buscando una función de biblioteca que iba a hacer esto.Supongo que es falta (si es que es) porque es bastante trivial de implementar:

let curry f a b c = f(a, b, c)

//overload resolution failure: there are two overloads with three arguments.
//let curryCompare = curry String.Compare

//This one might be more useful; it works because there's only one 3-argument overload
let backCurry f a b c = f(c, b, a)
let intParse = backCurry Int32.Parse
let intParseCurrentCultureAnyStyle = intParse CultureInfo.CurrentCulture NumberStyles.Any
let myInt = intParseCurrentCultureAnyStyle "23"
let myOtherInt = intParseCurrentCultureAnyStyle "42"

Para conseguir alrededor de la insuficiencia de la Cadena.Comparar, ya que como lo que yo puedo decir que no hay forma de especificar los cuales 3 con el argumento de sobrecarga para elegir, usted puede utilizar una solución general:

let curryCompare s1 s2 (b:bool) = String.Compare(s1, s2, b)
let backwardsCurryCompare (b:bool) s1 s2 = String.Compare(s1, s2, b)

No voy a entrar en detalle acerca de los usos de la función parcial de la aplicación en F# porque las otras respuestas han cubierto ya.

Es un proceso bastante sencillo.Tomar una función, se unen en uno de sus argumentos y devuelve una nueva función.Por ejemplo:

let concatStrings left right = left + right
let makeCommandPrompt= appendString "c:\> "

Ahora alarmada por el simple concatStrings función, usted puede agregar fácilmente un DOS estilo de símbolo del sistema para la parte delantera de cualquier cadena!Realmente útil!

Bueno, no realmente.Un caso que me parece es que cuando quiero tener una hacer una función que me devuelve los datos en una secuencia de igual manera.

let readDWORD array i = array[i] | array[i + 1] << 8 | array[i + 2] << 16 | 
    array[i + 3] << 24 //I've actually used this function in Python.

La parte conveniente es que en lugar de crear una clase completa para este tipo de cosas, llamar al constructor, llamando obj.readDWORD(), sólo tiene una función que no puede ser mutado de debajo de usted.

Usted sabe que usted puede asignar una función a través de una lista?Por ejemplo, la asignación de una función para agregar uno a cada elemento de una lista:

> List.map ((+) 1) [1; 2; 3];;
val it : int list = [2; 3; 4]

Esto es en realidad ya está utilizando alarmada porque el (+) el operador se utiliza para crear una función para agregar uno a su argumento, pero usted puede exprimir un poco más fuera de este ejemplo alterando a asignar la misma función de una lista de listas:

> List.map (List.map ((+) 1)) [[1; 2]; [3]];;
val it : int list = [[2; 3]; [4]]

Sin alarmada que no podía parcialmente aplicar estas funciones y tendría que escribir algo como esto en su lugar:

> List.map((fun xs -> List.map((fun n -> n + 1), xs)), [[1; 2]; [3]]);;
val it : int list = [[2; 3]; [4]]

Me dio un buen ejemplo de la simulación alarmada en C# en mi blog.Lo esencial es que usted puede crear una función que se cierra sobre un parámetro (en mi ejemplo crear una función para calcular el impuesto sobre las ventas se cerraron sobre el valor de un determinado municipio)fuera de un multi-parámetro de la función.

Lo que es interesante aquí es que en lugar de tener que hacer una función específicamente para el cálculo de impuesto a las ventas en el Condado de Cook, puede crear (y reutilizar) la función de forma dinámica en tiempo de ejecución.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top