Подтвердить что ты не робот

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

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

4b9b3361

Ответ 1

Функция 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)]

Ответ 2

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

Ответ 3

Альтернативой Text.Printf, альтернативной типу, является пакет formatting. 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, эти перезаписи вам будут рекомендованы.