将元组的元素作为Haskell中的参数传递给函数?

问题描述:

在我的Haskell程序中,我想使用printf格式化元组列表。我可以映射printf的一个列表,在这样的时刻,打印出的值之一:将元组的元素作为Haskell中的参数传递给函数?

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

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

我希望能够做这样的事情:

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 

但是,这传递一个元组printf,而不是两个单独的值。我怎么能把这个元组变成printf的两个参数?

+0

相关http://stackoverflow.com/q/6237259/168034 – phunehehe 2014-06-11 01:40:00

函数uncurry将双参数(curried)函数转换为成对函数。下面是它的类型签名:

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

您需要使用它printf,就像这样:

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

另一种解决方案是使用模式匹配来解构元组,像这样:

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

更好的选择是类型安全的格式化包,在我的答案中显示; http://stackoverflow.com/a/32848676/235908 – 2015-09-29 16:00:57

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

Text.Printf的类型安全替代方案是formatting p ackage。 Text.Printf.printf在编译时不能确保格式参数的数量与参数的数量及其类型一致。有关示例,请阅读Chris Done的文章What's wrong with printf?

使用示例:

{-# 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), ...] 

它需要GHC扩展OverloadedStrings才能正常工作。

虽然formatToString ("Value: " % int % " " % int)的类型为Int -> Int -> String,但解开它给出的类型为(Int, Int) -> String其中的输入类型与列表中的元素匹配。

重写过程可以分解;假设f = formatString ("Value: " ...)

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

即,首先你uncurry F至达到接受元组的功能,然后执行自\(x,y) -> uncurry f (x,y)常规Eta-conversion相当于简单地uncurry f。要打印结果中的每一行,使用mapM_

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

如果运行hlint YourFile.hs,这些重写将被推荐给你。