Передавать элементы кортежа в функцию в качестве аргументов в Haskell? - PullRequest
20 голосов
/ 25 февраля 2011

В моей программе на Haskell я хочу использовать printf для форматирования списка кортежей.Я могу сопоставить printf со списком, чтобы распечатывать значения по одному:

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?

Ответы [ 3 ]

42 голосов
/ 25 февраля 2011

Функция uncurry преобразует функцию с двумя аргументами (карри) в функцию на парах. Вот его тип подписи:

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)]
3 голосов
/ 25 февраля 2011
mapM_ (\(x,y) -> printf "Value: %d %d\n" x y) [(1,100),(2,350),(3,600),(4,200)]
2 голосов
/ 29 сентября 2015

Безопасной альтернативой Text.Printf является пакет для форматирования . Text.Printf.printf не гарантирует, что во время компиляции количество параметров форматирования совпадает с количеством аргументов и их типов. Прочитайте статью Криса Донца, Что не так с 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)

То есть сначала вы не спешите f для достижения функции, которая принимает кортежи, а затем выполняете обычное Eta-преобразование , поскольку \(x,y) -> uncurry f (x,y) эквивалентно просто uncurry f. Чтобы напечатать каждую строку в результате, используйте mapM_:

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

Если вы запустите hlint YourFile.hs , вам будут рекомендованы эти изменения.

...