Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 将列表中的相邻元素放入元组_Haskell_Purescript - Fatal编程技术网

Haskell 将列表中的相邻元素放入元组

Haskell 将列表中的相邻元素放入元组,haskell,purescript,Haskell,Purescript,给出一个元素列表: xs = [a, b, c, d, ... z] 其中a、b、c等是任意值的占位符。 我想实现一个函数邻接::[a]->[(a,a)],它产生 adjacentValues = [(a, b), (b, c), (c, d), ... (y, z)] 在Haskell中,递归定义相当简洁: adjacents :: [a] -> [(a, a)] adjacents (x:xs) = (x, head xs) : adjacents xs adjacents []

给出一个元素列表:

xs = [a, b, c, d, ... z]
其中
a、b、c
等是任意值的占位符。 我想实现一个函数
邻接::[a]->[(a,a)]
,它产生

adjacentValues = [(a, b), (b, c), (c, d), ... (y, z)]

在Haskell中,递归定义相当简洁:

adjacents :: [a] -> [(a, a)]
adjacents (x:xs) = (x, head xs) : adjacents xs
adjacents [] = []
Purescript有点冗长:

adjacents :: forall a. List a -> List (Tuple a a)
adjacents list = case uncons list of 
    Nothing -> []
    Just {head: x, tail: xs} -> case head xs of
                                     Just next -> Tuple x next : adjacents xs
                                     Nothing -> []
有没有一种不使用显式递归(使用折叠)来表示邻接的方法



免责声明:这个问题有Purescript和Haskell标签,因为我想向更广泛的读者开放它。我认为答案不依赖于Haskell的惰性计算语义,因此在两种语言中都是有效的

在Haskell中,无需显式递归,就可以用尾部压缩列表

   let a = [1,2,3,4,5,6,7,8,9,0]

   a `zip` tail a

   => [(1,2),(2,3),(3,4),(4,5),(5,6),(6,7),(7,8),(8,9),(9,0)]

出于完整性考虑,Purescript解决方案:

adjacent :: forall n. List n -> List (Tuple n n)
adjacent list = zip list $ fromMaybe empty $ tail list
可以更优雅地表示为:

adjacent :: forall n. List n -> List (Tuple n n)
adjacent list = zip list $ drop 1 list

为了便于说明(基于
zip
的解决方案肯定更好),下面是以展开形式编写的显式递归Haskell解决方案。我无缘无故地把它做成了一行

{-# LANGUAGE LambdaCase #-}

import Data.List (unfoldr)

adjacent :: [a] -> [(a, a)]
adjacent = unfoldr (\case { x:y:ys -> Just ((x, y), ys); _ -> Nothing })

(注意,这里的模式匹配奇数个元素的句柄列表而不会崩溃。)

既然我们已经看到了
zip
unbover
,我们应该有一个使用
foldr

adjacent :: [a] -> [(a,a)]
adjacent xs = foldr go (const []) xs Nothing
  where
    go a r Nothing = r (Just a)
    go a r (Just prev) = (prev, a) : r (Just a)
现在,因为每一个玩具问题都需要一个过度设计的解决方案,下面是您可以用来获得双面列表融合的方法:

import GHC.Exts (build)

adjacent :: [a] -> [(a,a)]
adjacent xs = build $ \c nil ->
  let
    go a r Nothing = r (Just a)
    go a r (Just prev) = (prev, a) `c` r (Just a)
  in foldr go (const nil) xs Nothing
{-# INLINE adjacent #-}

使用状态折叠,其中状态是最后一对项目:

在哈斯克尔:

import Data.List (mapAccumL)

adjacents :: [a] -> [(a, a)]
adjacents [] = []
adjacents (x:xs) = snd $ mapAccumL op x xs
    where
        op x y = (y, (x,y))

也可以使用
(>)
-
fg
=
\x->fx(gx)
tail
在空列表上崩溃的
应用程序
实例将其无点写入
相邻=zip tail
a`zip`drop 1a
是避免这种情况的一种方法。是的,整个表达式都可以工作,因为lazy haskell在创建第一个列表时不计算zip的第二个参数empty@NazariiBardiuk的确(我有时会因为假装头和尾不存在而忽略这些事情。)@duplode,我希望尾只是下降1的简写。有没有理由不这样做?
from maybe empty(tail list)
(在Haskell中可能拼写为
maybe[]snd(uncon list)
)相当于
drop 1 list
。是的,一想起来显然是正确的。也更可读,谢谢!顺便说一句,我建议你把你的解决方案转移到一个答案上来。