如何缩短像这样的Haskell实现?

hey*_*yyo 3 haskell

我有一个功能,有很多看起来像这样的警卫:

function 
    | p `elem` [0,1,2,3,4,5,6] = [0,1,2,3,4,5,6]
    | p `elem` [7,8,9,10,11,12,13] = [7,8,9,10,11,12,13]
    | p `elem` [14,15,16,17,18,19,20] = [14,15,16,17,18,19,20]
    | otherwise = []
Run Code Online (Sandbox Code Playgroud)

我确信我可以用Haskell写得更短.如果没有,那就没关系.我是Haskell的新手,我希望通过学习不同的方法来改善它.

也许使用"地图"可能是一个好的开始?但是,我不确定如何传递这些特定的列表.

值并不总是连续的.

Wil*_*sem 6

简单边界检查怎么样?

function p
    | p < 0 = [] 
    | p < 7 = [0..6]
    | p < 14 = [7..13]
    | p < 21 = [14..20]
    | otherwise = []
Run Code Online (Sandbox Code Playgroud)

它会更快,并且对于某些应用程序使用更少的内存.

如果您不想执行边界检查(但是元素检查),您仍然可以使用缩短的列表表示法.


或者,您可以构造一个迭代列表的辅助函数:

helper (x:xs) p | elem p x = x
                | otherwise = helper xs p 
helper [] _ = []

function = helper [[0..6],[7..13],[14..20]]
Run Code Online (Sandbox Code Playgroud)

虽然这实际上更长,但您可以轻松扩展function以使用其他列表.但请注意,此函数将更慢,因为elem需要O(n)时间,而边界检查需要O(1)时间.


您也可以 - 正如@ jamshidh的回答中所建议的那样,构建一个Data.Map保证O(log n)查找时间的数据结构:

import Data.Map (Map)
import qualified Data.Map as Map
import Data.Maybe(fromMaybe)

helper2 :: Ord a => [[a]] -> a -> [a]
helper2 lst p = fromMaybe [] $ Map.lookup p (Map.fromList $ concatMap (\x -> zip x (repeat x)) lst)

function = helper2 [[0..6],[7..13],[14..20]]
Run Code Online (Sandbox Code Playgroud)

对于最后一篇文章,它(\x -> zip x (repeat x))为包含列表元素e和整个列表的列表元组生成生成l.例如:

Prelude> (\x -> zip x (repeat x)) [0..6]
[(0,[0,1,2,3,4,5,6]),(1,[0,1,2,3,4,5,6]),(2,[0,1,2,3,4,5,6]),(3,[0,1,2,3,4,5,6]),(4,[0,1,2,3,4,5,6]),(5,[0,1,2,3,4,5,6]),(6,[0,1,2,3,4,5,6])]
Run Code Online (Sandbox Code Playgroud)

其工作方式如下:x例如[0,1,2,3,4,5,6],与列表统一,现在我们在无限列表zip[0,1,2,3,4,5,6]和上面应用函数[[0,1,2,3,4,5,6],[0,1,2,3,4,5,6],[0,1,2,3,4,5,6],....].zip只要两个列出feed元素,就生成元组,因此它从第一个元素[0,1,..,6]和第一个元素中获取[[0,1,..,6],[0,1,..,6],[0,1,..,6],...]结果元组(0,[0..6]),接下来它1从列表中获取第二个元素repeat,从而获取函数中的第二个元素(1,[0..6]).它一直这样做 - 虽然懒惰 - 直到其中一个列表用尽,这是第一个列表的情况.


che*_*ner 5

您可以在此处使用列表monad.

func p = join $ do x <- [[1,3,5], [2,4,6], [7,8,9]]
                   guard $ p `elem` x
                   return x
Run Code Online (Sandbox Code Playgroud)

列表列表是您要检查的内容.guard过滤掉未成功选择的调用.只要候选人名单不相交,最多一个人就会成功.return x评估其中一个[][x]两个选项之一x,因此join 减少[x][].

> func 1
[1,3,5]
> func 2
[2,4,6]
> func 7
[7,8,9]
> func 10
[]
Run Code Online (Sandbox Code Playgroud)

作为列表理解,它看起来像

func p = join [x | x <-[[1,3,5],[2,4,6],[7,8,9]], p `elem` x]
Run Code Online (Sandbox Code Playgroud)