2011-02-25 20 views
17

En mi programa Haskell, quiero usar printf para formatear una lista de tuplas. Puedo mapa printf más de una lista para imprimir los valores de uno en un momento como este:¿Alimentar elementos de una tupla a una función como argumentos en Haskell?

mapM_ (printf "Value: %d\n") [1,2,3,4] 

Value: 1 
Value: 2 
Value: 3 
Value: 4 

Quiero ser capaz de hacer algo como esto:

mapM_ (printf "Values: %d %d\n") [(1,100),(2,350),(3,600),(4,200)] 

Values: 1 100 
Values: 2 350 
Values: 3 600 
Values: 4 200 

Pero esto pasa una tupla de printf, no dos valores separados. ¿Cómo puedo convertir la tupla en dos argumentos para printf?

+0

relacionado http://stackoverflow.com/q/6237259/168034 – phunehehe

Respuesta

36

Función uncurry convierte una función de dos argumentos (curried) en una función en pares. Esto es su tipo de firma:

uncurry :: (a -> b -> c) -> (a, b) -> c 

Es necesario usarlo en printf, así:

mapM_ (uncurry $ printf "Values: %d %d\n") [(1,100),(2,350),(3,600),(4,200)] 

Otra solución es utilizar la coincidencia de patrones para deconstruir la tupla, como esto:

mapM_ (\(a,b) -> printf "Values: %d %d\n" a b) [(1,100),(2,350),(3,600),(4,200)] 
+0

Una mejor alternativa es el paquete de formato de tipo seguro demostrado en mi respuesta a continuación; http://stackoverflow.com/a/32848676/235908 –

3
mapM_ (\(x,y) -> printf "Value: %d %d\n" x y) [(1,100),(2,350),(3,600),(4,200)] 
2

Una alternativa segura de tipo a Text.Printf es la formatting p Ackage. Text.Printf.printf no garantiza en tiempo de compilación que el número de parámetros de formato se alinee con la cantidad de argumentos y sus tipos. Lea el artículo de Chris Done, What's wrong with printf? para ver ejemplos.

Un ejemplo de uso:

{-# LANGUAGE OverloadedStrings #-} 
import Formatting 

map (uncurry $ formatToString ("Value: " % int % " " % int)) [(1,100), (2,350), ...] 
map (\(x,y) -> formatToString ("Value: " % int % " " % int) x y) [(1,100), (2,350), ...] 

Se requiere la extensión GHC OverloadedStrings para funcionar correctamente.

Mientras que formatToString ("Value: " % int % " " % int) tiene el tipo , al desagrupar da el tipo (Int, Int) -> String cuyo tipo de entrada coincide con los elementos de la lista.

El proceso de reescritura se puede desglosar; suponiendo f = formatString ("Value: " ...),

map (\(x,y) -> f x y) ≡ map (\(x,y) -> uncurry f (x,y)) ≡ map (uncurry f) 

Esto es, primero que f uncurry para lograr la función que acepta tuplas, y luego realizar un habitual Eta-conversion desde \(x,y) -> uncurry f (x,y) es equivalente a simplemente uncurry f. Para imprimir cada línea en el resultado, utilice mapM_:

mapM_ (putStrLn . uncurry $ formatToString ...) [(1,100), (2,350), ...] 

Si ejecuta YourFile.hs hlint, estas reescrituras serán recomendados para usted.

Cuestiones relacionadas