Элементы кортежа кортежа функции в качестве аргументов в Haskell?

17

В моей программе 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?

    
задан davidscolgan 25.02.2011 в 14:45
источник
  • related stackoverflow.com/q/6237259/168034 –  phunehehe 11.06.2014 в 03:40

3 ответа

36

Функция 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)]
    
ответ дан Miikka 25.02.2011 в 15:01
  • Лучшей альтернативой является пакет безопасного форматирования, продемонстрированный в моем ответе ниже; stackoverflow.com/a/32848676/235908 –  Simon Shine 29.09.2015 в 18:00
3
mapM_ (\(x,y) -> printf "Value: %d %d\n" x y) [(1,100),(2,350),(3,600),(4,200)]
    
ответ дан Landei 25.02.2011 в 15:06
2

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

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

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

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

    
ответ дан Simon Shine 29.09.2015 в 17:59