我编写了以下函数,以在给定的Snoc列表中找到第N个元素(反向缺点),但我认为这不是解决该问题的最佳方法。我想知道您是否愿意分享一些见解,代码或建议,以寻求不同的解决方案?您可能会考虑的一种方法可以更有效地完成工作:
这是我的职能:
data ListS a = NilS
|Snoc (ListS a) a deriving Show
len :: ListS a -> Int
len NilS = 0
len (Snoc a b) = 1 + len(a)
nthElementS :: Int -> ListS a -> a
nthElementS _ NilS = error "Empty List"
nthElementS n s = if n < 0 || n >= len(s) then error "Invalid Index"
else nthAux ((len(s)-1)-n) s where
nthAux 0 (Snoc a b) = b
nthAux m (Snoc a b) = nthAux (m-1) a
一些例子:
Main> nthElementS 0 (Snoc (Snoc (Snoc (Snoc (Snoc NilS 1) 2) 3) 4) 5)
1
Main> nthElementS 2 (Snoc (Snoc (Snoc (Snoc (Snoc NilS 1) 2) 3) 4) 5)
3
作为附加查询:实现将2个Snoc列表串联的功能的最佳方法是什么?我已经在考虑一种解决方案,但是它需要一个辅助功能来跟踪第N个位置,再次,我觉得这不会充分利用Haskell相对于其他语言的优势。
谢谢。
答案 0 :(得分:4)
我们可以使用“ 尝试和错误”方法,首先尝试在“前缀列表”中查找该元素,如果这还不够的话(因为索引较大) ,然后尝试当前元素。如果这还不够,则由“家长电话”来处理这种情况。为此,我们可以先定义一个输出类型稍有不同的函数:
nthShelp :: Int -> ListS a -> Either a Int
因此,如果找到了元素(Left x
是元素),则返回x
,或者找到所需的“剩余”元素Right
n , with
n`穿过。
因此我们可以使用以下方式定义它:
nthShelp :: Int -> ListS a -> Either a Int
nthShelp n NilS = Right n
nthShelp n (Snoc hs t) = progress nhs
where nhs = nthElementS n hs
progress lx@(Left _) = lx
progress (Right 0) = Left t
progress (Right n) = Right (n-1)
因此,我们首先在列表的开头进行递归调用,然后通过递减索引直到索引达到零来解决递归调用,在这种情况下,我们返回相应的Left t
和那个{{1} },然后从递归调用中传回。
我们可以利用Left t
是Either a
等式这一事实,并将其写得更有效,例如:
Monad
然后我们可以用nthShelp :: Int -> ListS a -> Either a Int
nthShelp n NilS = Right n
nthShelp n (Snoc hs t) = nthElementS n hs >>= progress
where progress 0 = Left t
progress n = Right (n-1)
来写nthElementS
:
nthShelp
就时间复杂度而言,它仍然是 O(n)(其中 n 是列表的 length ,而不是我们的索引想获得)。无法用这种数据结构做得更好,因为我们需要知道前缀中的元素数量,然后才能知道返回哪个元素。
作为附加查询:实现将2个Cons列表串联的功能的最佳方法是什么?我已经在考虑一种解决方案,但是它需要一个辅助功能来跟踪第N个位置,再次,我觉得这不会充分利用Haskell相对于其他语言的优势。
好吧,您可以在这里看到一个串联,是将 second 列表的(通常是很深)嵌套的nthElementS :: Int -> ListS a -> a
nthElementS n l | n < 0 = error "Index too small"
| Left a <- nthShelp n l = a
| otherwise = error "Index too large"
替换为第一个列表。因此,如果我们串联NlS
,则为concatS l1 NilS
,如果我们串联l1
,则为concatS l1 (Snoc NilS x)
。因此我们可以将其递归定义为:
Snic l1 x)
上述方法的缺点是,如果第一个列表为concatS :: ListS a -> ListS a -> ListS a
concatS l1 NilS = l1
concatS l1 (Snoc l2 x) = Snoc (concatS l1 l2) x
(太空),它仍然可以在 O(n)中工作。我们可以为此添加保护措施,以解决这种情况:
NilS