Как преобразовать список в кортеж в Haskell?
Как лучше всего преобразовать список в кортеж в Haskell:
[1,2,3,4,5,6] -> (1,2,3,4,5,6)
- Список различных типов?
- Возможно ли программирование графического интерфейса?
- DatatypeContexts Устарела в последнем GHC: Почему?
- Как функторы работают в haskell?
- Кабал не устанавливает зависимости при необходимости профилирования библиотек?
- Почему Хаскелл (иногда) называют «Лучшим императивным языком»?
- Использует функцию Haskell id
- Что такое class Comonad в Haskell?
- Что такое «|» в определении classа Haskell?
- Заказ параметров для использования каррирования
- Сравнение веб-фреймворков Haskell Snap и Yesod
- Интегральные операторы quot vs. div
- Недостаточная производительность Haskell foldl с (++)
В общем, вы не можете. Каждый размер кортежа является отдельным типом, тогда как списки любой длины – это один тип. Таким образом, нет хорошего способа написать функцию, которая берет список и возвращает кортеж той же длины – у него не было бы корректного типа возврата.
Например, у вас могут быть такие функции, как:
tuplify2 :: [a] -> (a,a) tuplify2 [x,y] = (x,y) tuplify3 :: [a] -> (a,a,a) tuplify3 [x,y,z] = (x,y,z)
… но не тот, который выполняет работу обоих.
Вы можете написать общую версию, используя различные виды метапрограмм, но вы редко этого хотели.
Обратите внимание, что эта же проблема относится и к другим вещам, таким как запись экземпляров classов для разных кортежей – посмотрите исходный код для Data.Tuple из стандартных библиотек!
Шаблон Haskell настолько близок, насколько вы можете получить из-за проверки типа, если вы хотите извлечь переменное число элементов, поскольку (a, b) и (a, b, c) имеют разные типы.
{-# LANGUAGE TemplateHaskell #-} import Language.Haskell.TH tuple :: Int -> ExpQ tuple n = do ns <- replicateM n (newName "x") lamE [foldr (\xy -> conP '(:) [varP x,y]) wildP ns] (tupE $ map varE ns)
Затем:
$(tuple 6) [1,2,3,4,5,6] == (1,2,3,4,5,6) $(tuple 3) "abc" == ('a','b','c')
Но в целом, если вам нужен этот ответ, тогда вы задаете неправильный вопрос где-нибудь.
Если вы просто хотите получить произвольный произвольный доступ, возможно, лучшим вариантом будет использование массива.
Если чувствуете, что я собираюсь посоветовать вам указывать пистолет на ногу и доверять вам не стрелять.
> list2Tuple lst = read $ "(" ++ (init.tail.show) lst ++ ")" > list2Tuple [1,2,3] :: (Int, Int, Int) (1,2,3) > list2Tuple [1,2,3,4] :: (Int, Int, Int, Int) (1,2,3,4)
Это будет работать до того, что будет определяться длиной и количеством строк и Show.
Кортежи и списки очень разные. О том, что вы можете сделать, это вручную написать функцию преобразования:
toTuple :: [a] -> (a,a,a,a,a,a) toTuple [a,b,c,d,e,f] = (a,b,c,d,e,f)
Обратите внимание, насколько различны типы: единственная переменная списка расширяется до шести переменных для кортежа. Таким образом, вам понадобится одна функция для каждого размера кортежа.
Мне сложно сделать убедительные объяснения манипуляций с шаблоном Хаскелла, но вот демонстрация:
> :m +Language.Haskell.TH > :set -XTemplateHaskell > runQ [| [1,2,3,4,5,6] |] >>= putStrLn . pprint [1, 2, 3, 4, 5, 6] > runQ [| [1,2,3,4,5,6] |] >>= \ (ListE exps) -> putStrLn (pprint (TupE exps)) (1, 2, 3, 4, 5, 6)
Я не думаю, что это возможно сделать в Haskell, для списка произвольной длины, неизвестной во время компиляции. Шаблон Haskell не может этого сделать, потому что он работает только во время компиляции. Я столкнулся с ситуацией, когда мне нужно было сделать именно это, и мне пришлось обходиться. Библиотека базы данных ожидает кортежей различной длины для аргументов запроса, но у меня есть список произвольной длины. Поэтому я должен обойти библиотечный интерфейс. Было бы неплохо, если бы он мог взять список.
В основном проблема заключается в том, что разные кортежи разных типов. Но компилятор Haskell должен знать в компиляторе, какие типы могут существовать во время выполнения. Преобразование списка произвольной длины в кортеж во время выполнения может создать некоторый тип, о котором он не знал во время компиляции.
На самом деле вы можете сделать лучше, чем вручную писать одну функцию для каждого размера, если вы используете квазикомиссию [1]. Тем не менее, я бы задался вопросом о коде, где вы ожидаете использовать это в целом.