Я делал большую работу с кортежами и списками кортежей недавно, и я задавался вопросом, разумен ли я.
Вещи чувствуют себя неловкими и неуклюжими, который для меня сигнализирует, что я делаю что-то не так.
Например, я записал три функции удобства для получения первого, второго и третьего значения в кортеже 3 значений.
Существует ли лучший способ, которым я отсутствую?
Есть ли более общие функции, которые позволяют Вам составлять и управлять данными кортежа?
Вот некоторые вещи, которые я пытаюсь сделать, то чувство должно быть generalisable.
Извлечение значений: я должен создать версию fst, snd, и т.д.... для кортежей размера два, три, четыре и пять, и т.д....?
fst3(x,_,_) = x
fst4(x,_,_,_) = x
Управление значениями: можно ли увеличить последнее значение каждого кортежа в списке пар и затем использовать ли ту же самую функцию для постепенного увеличения последнего значения каждого кортежа в списке, утраивается?
Архивирование и Разархивация значений: существует zip и zip3. Мне также нужен zip4? или есть ли некоторый способ создать общую функцию zip?
Извините, если это кажется субъективным, я честно не знаю, возможно ли это даже или если я трачу впустую свое время, пишущий 3 дополнительным функциям каждый раз, когда мне нужно общее решение.
Спасибо за любую справку можно дать!
Когда у меня появляются большие кортежи, я использую жалкое оправдание Haskell для синтаксиса записи, чтобы дать каждому element имя, например,
data LatticeOperations a = LO { bot :: a
, top :: a
, glb :: a
, lub :: a
, le :: a
}
Это кортеж из пяти элементов, но имена превращаются в функции, которые выбирают отдельные элементы.
Для изменения кортежей у вас есть синтаксис обновления записи. В примере, который я только что привел, нет смысла заменять только один элемент, но я мог бы, например, уточнить частичный порядок и заменить три элемента
lattice { le = le', glb = glb', lub = lub' }
И, конечно, если у вас есть большая запись и вы просто пытаетесь для увеличения вы можете сделать что-то вроде
data FatRecord = FR { count :: Int, ... }
fat = fat { count = count fat + 1 }
Я не думаю, что синтаксис записи помогает с zip и unzip.
Нет способа обобщить кортеж -size без использования расширений, таких как Template Haskell. Итак, если мы просто рассмотрим простой haskell: да, вам нужно написать версии fst
и т. Д. Для каждого размера кортежа, и нет, вы не можете написать общий метод zip.
Да, вам нужно написать fstN
себя.Но почему бы не извлечь его при сопоставлении с образцом?
Data.List уже предоставляет до zip7
. Для общего zipN
используйте ZipList.
См. Как заархивировать несколько списков в Haskell? .
Не без расширений. Поскольку все кортежи имеют разные типы, вам необходимо создать класс типа, например:
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FunctionalDependencies #-}
class Firstable a b c | a -> b, a -> c where
firstOf :: a -> b
restOf :: a -> c
concatenate :: b -> c -> a
instance Firstable [a] a [a] where
firstOf = head
restOf = tail
concatenate = (:)
instance Firstable (a,b) a b where
firstOf = fst
restOf = snd
concatenate = (,)
instance Firstable (a,b,c) a (b,c) where
firstOf (x,_,_) = x
restOf (_,x,y) = (x,y)
concatenate x (y,z) = (x,y,z)
instance Firstable (a,b,c,d) a (b,c,d) where
firstOf (x,_,_,_) = x
restOf (_,x,y,z) = (x,y,z)
concatenate x (y,z,w) = (x,y,z,w)
instance Firstable (a,b,c,d,e) a (b,c,d,e) where
firstOf (x,_,_,_,_) = x
restOf (_,x,y,z,w) = (x,y,z,w)
concatenate x (y,z,w,t) = (x,y,z,w,t)
Затем вы можете использовать
incFirst :: (Num b, Firstable a b c) => a -> a
incFirst x = (1 + firstOf x) `concatenate` restOf x
main = do
print $ map incFirst [(1,2),(3,4),(5,6)]
print $ map incFirst [(1,3,6,7),(2,5,-2,4)]
( lastOf
аналогично.)
Но почему бы не использовать отдельные функции ?
Как только кортежи становятся больше размера 3 или около того, и/или один и тот же тип кортежа начинает широко использоваться, лучше использовать запись.
Встроенные в Haskell fst
и snd
поддерживают только пары кортежей, поэтому вы вправе определить свои собственные. Если вы хотите увеличить последнее значение в списке, разверните список, работайте с этого конца и разверните его обратно. Если вы хотите, чтобы инкремент работал для списков и списков кортежей, просто определите новую функцию инкремента для этих типов данных и вызовите ее внутри вашей функции инкремента для списка. @KennyTM ответил на вопрос zipN
.
Работа со списками и кортежами в Haskell немного отличается от многих языков, но через некоторое время они ощущаются особенно естественными и мощными по сравнению с ними.