Haskell中的简单列表连接函数(intersperse)[duplicate]

juzqafwq  于 2023-06-30  发布在  其他
关注(0)|答案(1)|浏览(129)

此问题已在此处有答案

How to reuse a type variable in an inner type declaration(4个答案)
4天前关闭。
我试着写一个 intersperse 函数,它接受一个a列表的列表,例如。字符串列表,以及一个单个a,例如char作为分隔符,并返回a的列表或String。
例如,如果我打电话

intersperse ',' ["a", "b"]
-- I will get "a,b"

intersperse ',' ["hello"]
-- I will get only "hello"

intersperse ',' ["a", "b", "c"]
-- I will get "a,b,c"

intersperse 1 [[2,3,4], [5,6,7]]
-- I will get [2, 3, 4, 1, 5, 6, 7]

intersperse 1 [[2,3], [4,5], [6,7]]
-- I will get [2, 3, 1, 4, 5, 1, 6, 7]
--

所以我写了如下,它工作正常。

intersperse :: a -> [[a]] -> [a]
intersperse s [] = []
intersperse s (x:[]) = x
intersperse s (x:xs) = loop x xs
  where loop a [] = a
        loop a (x:xs) = loop (a ++ [s] ++ x) xs

但是如果我在循环函数中添加类型签名,它将无法编译,并且我无法意识到哪里出错了

intersperse :: a -> [[a]] -> [a]
intersperse s [] = []
intersperse s (x:[]) = x
intersperse s (x:xs) = loop x xs
  where loop :: [a] -> [[a]] -> [a]
        loop a [] = a
        loop a (x:xs) = loop (a ++ [s] ++ x) xs
9udxz4iz

9udxz4iz1#

但是如果我在循环函数中添加类型签名,它将无法编译,我无法意识到哪里出错了。
这是因为where子句中的a与顶层的a不同。您可以启用**ScopedTypeVariables**扩展[ghc-doc]:

{-# LANGUAGE ScopedTypeVariables #-}

intersperse :: forall a. a -> [[a]] -> [a]
intersperse s [] = []
intersperse s (x : []) = x
intersperse s (x : xs) = loop x xs
  where
    loop :: [a] -> [[a]] -> [a]
    loop a [] = a
    loop a (x : xs) = loop (a ++ [s] ++ x) xs

然而,intersperse函数并不是懒惰地编写的,这意味着对于大型列表,在将结果交给调用者之前将花费大量时间,并且将消耗大量内存,并且对于无限列表,它将进入无限循环,当内存耗尽时将结束。
您可以使用以下命令优化函数:

intersperse :: a -> [[a]] -> [a]
intersperse s [] = []
intersperse s [x] = x
intersperse s (x : xs) = x ++ go xs
  where
    go [] = []
    go (x : xs) = s : x ++ go xs

相关问题