web-dev-qa-db-ja.com

Haskellでリストをタプルに変換するにはどうすればよいですか?

Haskellでリストをタプルに変換するにはどうすればよいですか?

[1,2,3,4,5,6] -> (1,2,3,4,5,6)
26
Alex

一般的にはできません。タプルの各サイズは異なるタイプですが、任意の長さのリストは単一のタイプです。したがって、リストを受け取り、同じ長さのタプルを返す関数を作成する良い方法はありません。明確に定義された戻り値の型はありません。

たとえば、次のような関数を使用できます。

tuplify2 :: [a] -> (a,a)
tuplify2 [x,y] = (x,y)

tuplify3 :: [a] -> (a,a,a)
tuplify3 [x,y,z] = (x,y,z)

...しかし、両方の仕事をするものではありません。

あなたはcanさまざまな種類のメタプログラミングを使用して汎用バージョンを作成できますが、作成することはめったにありません。

同じ問題が、さまざまなタプルのクラスインスタンスの記述など、他のものにも当てはまることに注意してください。標準ライブラリの Data.Tupleのソースコード を見てください。

47
C. A. McCann

テンプレート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 (\x y -> 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')

しかし、一般的に、この答えが必要な場合は、どこかで間違った質問をしていることになります。

フラットランダムアクセスが必要な場合は、配列を使用することをお勧めします。

24
Edward KMETT

私があなたに銃をあなたの足に向けて、あなたが撃たないことを信頼するように忠告しようとしているように感じるならば。

> 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)

これは、タプルの表示と読み取りが定義されている長さまで機能します。

11
Davorak

タプルとリストは非常に異なるものです。できる最善の方法は、変換関数を手動で作成することです。

toTuple :: [a] -> (a,a,a,a,a,a)
toTuple [a,b,c,d,e,f] = (a,b,c,d,e,f)

タイプの違いに注意してください。リストの単一の変数は、タプルの6つの変数に展開されます。したがって、タプルのサイズごとに1つの関数が必要になります。

Template Haskellの操作について説得力のある説明をするのは難しいと思いますが、ここにデモンストレーションがあります。

> :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)
5
David Fox

コンパイル時にわからない任意の長さのリストのため、Haskellでこれを行うことは不可能だと思います。テンプレートHaskellはコンパイル時にのみ動作するため、それを行うことはできません。私はこれを正確に行う必要がある場合に遭遇し、それを回避する必要がありました。データベースライブラリは、クエリ引数に異なる長さのタプルを想定していますが、任意の長さのリストがあります。そのため、ライブラリインターフェイスを回避する必要があります。それがリストを取ることができればそれは素晴らしいでしょう。

基本的に問題は、異なる長さのタプルが異なるタイプであるということです。しかし、Haskellコンパイラはコンパイル型で実行時にどの型が存在するかを知る必要があります。実行時に任意の長さのリストをタプルに変換すると、コンパイル時に知らなかったタイプが作成される可能性があります。

3
Lyle Kopnicky

実際、準引用を使用する場合は、タプルサイズごとに1つの関数を手動で記述するよりも優れています ここで説明 。ただし、これを一般的に使用する予定のコードについては疑問に思います。

2
StevenC