What is the easiest way to turn a known-length list into nested pairs in Haskell?

How to convert a list with a known length into nested pairs? In other words, what is the most convenient way to fill holes like below?

_ [1,2]       :: (Int,Int)
_ [1,2,3]     :: ((Int,Int),Int)
_ [1,2,3,4]   :: (((Int,Int),Int),Int)
_ [1,2,3,4,5] :: ((((Int,Int),Int),Int),Int)

EDIT: please note that the type holes do not have to be the same function, I am looking for a convenient template (if there is a convenient pattern) to fill the holes.

+4
source share
5 answers

Perhaps so:

step f xs = (f (init xs), last xs)
len1 = head
len2 = step len1
len3 = step len2
len4 = step len3

In ghci:

*Main> len4 [1..4]
(((1,2),3),4)

You can, of course, also directly implement one of these functions with pattern matching:

len4' [a,b,c,d] = (((a,b),c),d)

It will also not go through the list as many times as there are elements, which is nice.

+7

. -, :

{-# LANGUAGE
  TemplateHaskell, DataKinds, ScopedTypeVariables,
  FlexibleInstances, PolyKinds, TypeOperators,
  TypeFamilies, GADTs, UndecidableInstances #-}

import Data.Singletons.TH
import qualified GHC.TypeLits as Lit

$(singletons [d| data Nat = Z | S Nat deriving (Eq, Show) |])

TH , TH . , ( ) - ( singletons).

tuplify , Nat.

type family NTup n a where
  NTup (S (S Z))     a = (a, a)
  NTup (S (S (S n))) a = (NTup (S (S n)) a, a)

tuplify :: Sing n -> [a] -> NTup n a
tuplify n as = go n (reverse as) where
  go :: Sing n -> [a] -> NTup n a
  go (SS (SS SZ))     [a, b] = (b, a)
  go (SS (SS (SS n))) (a:as) = (go (SS (SS n)) as, a)
  go _                _      = error "tuplify: length mismatch"

:

tuplify (SS (SS (SS SZ))) [1, 2, 3] -- ((1, 2), 3)

naturals , - :

type family N n where
  N 0 = Z
  N n = S (N (n Lit.- 1))

type SN n = Sing (N n)

:

tuplify (sing:: SN 10) [1..10] -- (((((((((1,2),3),4),5),6),7),8),9),10)

, () ( ), :

type family NTup n a where
  NTup Z     a = ()
  NTup (S n) a = (NTup n a, a)

tuplify :: Sing n -> [a] -> NTup n a
tuplify n = go n . reverse where
  go :: Sing n -> [a] -> NTup n a
  go SZ     []     = ()
  go (SS n) (a:as) = (go n as, a)
  go _      _      = error "tuplify: length mismatch"

tuplify (sing:: SN 5) [1..5] -- ((((((),1),2),3),4),5)
+5

. Haskell - ( )

class C a b where
   listToTuple :: [a] -> b

instance C a a where
   listToTuple [x] = x

instance C a b => C a (b,a) where
   listToTuple xs = (listToTuple (init xs), last xs)

:

> listToTuple [1..3::Int] :: ((Int,Int),Int)
((1,2),3)
> listToTuple [0..3::Int] :: (((Int,Int),Int),Int)
(((0,1),2),3)

, , Haskell , . , . , , ( GADT).

+4

​​ , , .

, .

:

data TupleList' r a = Value r | Tuple (TupleList' (r, a) a)
  deriving (Show, Read, Eq, Ord)

type TupleList = TupleList' ()

, TupleList a (), ((), a), (((), a), a) .., , Tuple Value.

:

fromList :: [a] -> TupleList a
fromList = loop ()
  where
    loop :: r -> [a] -> TupleList' r a
    loop r [] = Value r
    loop r (x:xs) = Tuple (loop (r, x) xs)

, loop ( , TupleList' - (r, a) -> [a] -> TupleList' (r, a) a.

: mapM_ (print . fromList) (inits [1..4])

Value ()
Tuple (Value ((),1))
Tuple (Tuple (Value (((),1),2)))
Tuple (Tuple (Tuple (Value ((((),1),2),3))))
Tuple (Tuple (Tuple (Tuple (Value (((((),1),2),3),4)))))
+4
source

The easiest way -

z   (x:xs) = x
s r (x:xs) = (x, r xs)
toTuples n xs = n xs

But it toTuplesreturns the pairs in the reverse order:

 toTuples (s (s (s z))) [1..] == (1,(2,(3,4)))

We can use CPS to fix this:

z   f  xs    = f ()
s r f (x:xs) = r (\p -> (f p, x)) xs
toTuples n (x:xs) = n (const x) xs

Then

toTuples (s (s (s z))) [1..] == (((1,2),3),4)

And we can define some syntactic sugar (I mostly sneak from Andras Kovacs answer):

{-# LANGUAGE TemplateHaskell, UndecidableInstances, DataKinds, GADTs, TypeFamilies, TypeOperators #-}

import Data.Singletons.TH
import GHC.TypeLits

$(singletons [d| data Nat = Z | S Nat deriving (Eq, Show) |])

z   f  xs    = f ()
s r f (x:xs) = r (\p -> (f p, x)) xs

toTuples n (x:xs) = n (const x) xs

type family Result n r a where
  Result  Z    r a = r
  Result (S n) r a = Result n (r, a) a

run :: Sing n -> (() -> r) -> [a] -> Result n r a
run  SZ     = z
run (SS sn) = s (run sn)

toTuplesN :: Sing n -> [a] -> Result n a a
toTuplesN sn (x:xs) = run sn (const x) xs

type family N n where
  N 0 = Z
  N n = S (N (n - 1))

type SN n = Sing (N (n - 1))

main = print $ toTuplesN (sing :: SN 6) [1..] -- (((((1,2),3),4),5),6)

Please note that the code also works for infinite lists, since there is no converse.

+2
source

Source: https://habr.com/ru/post/1584374/


All Articles