Reh*_*que 4 haskell tuples list
如何将具有已知长度的列表转换为嵌套对?换句话说,填充下面的类型孔最方便的方法是什么?
_ [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)
Run Code Online (Sandbox Code Playgroud)
编辑:请注意,类型孔不必是相同的功能,我正在寻找一个方便的模式(如果存在方便的模式)来填补空洞.
也许是这样的:
step f xs = (f (init xs), last xs)
len1 = head
len2 = step len1
len3 = step len2
len4 = step len3
Run Code Online (Sandbox Code Playgroud)
在ghci:
*Main> len4 [1..4]
(((1,2),3),4)
Run Code Online (Sandbox Code Playgroud)
当然也可以通过模式匹配直接实现这些功能之一:
len4' [a,b,c,d] = (((a,b),c),d)
Run Code Online (Sandbox Code Playgroud)
这也不会像有元素一样遍历列表,这很好.
与依赖类型的版本一起使用.首先,让我们完成样板:
{-# 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) |])
Run Code Online (Sandbox Code Playgroud)
这里使用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"
Run Code Online (Sandbox Code Playgroud)
尝试一下:
tuplify (SS (SS (SS SZ))) [1, 2, 3] -- ((1, 2), 3)
Run Code Online (Sandbox Code Playgroud)
现在写出自然是非常艰巨的,所以让我们介绍一些语法糖:
type family N n where
N 0 = Z
N n = S (N (n Lit.- 1))
type SN n = Sing (N n)
Run Code Online (Sandbox Code Playgroud)
现在:
tuplify (sing:: SN 10) [1..10] -- (((((((((1,2),3),4),5),6),7),8),9),10)
Run Code Online (Sandbox Code Playgroud)
作为旁注,如果我们将空列表转换为()(从而也允许单元素嵌套元组),我们的定义会变得更加自然:
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)
Run Code Online (Sandbox Code Playgroud)