首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何缩短这样的Haskell实现?

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

Stack Overflow用户
提问于 2016-04-27 00:46:24
回答 3查看 253关注 0票数 3

我有一个功能,有很多警卫,看上去像这样:

代码语言:javascript
复制
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 = []

我相信我能用Haskell写得更短。如果没有,那就没事了。我是哈斯克尔的新手,我希望通过学习不同的方法来做得更好。

也许使用“地图”可能是一个好的开始?但是,我不知道如何传递那些特定的清单。

这些值并不总是连续的。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-04-27 00:54:03

简单的边界检查呢?

代码语言:javascript
复制
function p
    | p < 0 = [] 
    | p < 7 = [0..6]
    | p < 14 = [7..13]
    | p < 21 = [14..20]
    | otherwise = []

它将更快,并对某些应用程序使用较少的内存。

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

或者,您可以构造一个对列表进行迭代的助手函数:

代码语言:javascript
复制
helper (x:xs) p | elem p x = x
                | otherwise = helper xs p 
helper [] _ = []

function = helper [[0..6],[7..13],[14..20]]

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

您还可以--正如在@jamshidh's answer中所建议的那样,构造一个Data.Map,它是一种保证O(log )查找时间的数据结构:

代码语言:javascript
复制
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]]

对于最后一部分,它生成(\x -> zip x (repeat x)),用于包含list e元素和整个list l元素的列表元组。例如:

代码语言:javascript
复制
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])]

它的工作方式如下:x与list统一,例如[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],[0,1,2,3,4,5,6],....]上应用zip函数。只要这两个列表提要元素都能生成元组,zip就会生成元组,因此它从[0,1,..,6]获取第一个元素,从[[0,1,..,6],[0,1,..,6],[0,1,..,6],...]获取第一个元素,因此得到的元组是(0,[0..6]),接下来它从列表中获取第二个元素1,从repeat函数获取第二个项目,因此是(1,[0..6])。它一直这样做--虽然懒洋洋的--直到其中一个列表被耗尽,这就是第一个列表的情况。

票数 6
EN

Stack Overflow用户

发布于 2016-04-27 01:19:55

你可以在这里用单子表。

代码语言:javascript
复制
func p = join $ do x <- [[1,3,5], [2,4,6], [7,8,9]]
                   guard $ p `elem` x
                   return x

列表是您想要检查的内容。对guard的调用过滤掉了那些没有成功的选择。只要候选人名单不相交,最多只能有一个人成功。return x的计算值为[][x],用于x的一种选择,因此join[x]简化为[]

代码语言:javascript
复制
> func 1
[1,3,5]
> func 2
[2,4,6]
> func 7
[7,8,9]
> func 10
[]

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

代码语言:javascript
复制
func p = join [x | x <-[[1,3,5],[2,4,6],[7,8,9]], p `elem` x]
票数 5
EN

Stack Overflow用户

发布于 2016-04-27 00:58:21

首先创建列表

代码语言:javascript
复制
lists = [[0,1,2,3,4,5,6], [7,8,9,10,11,12,13], [14,15,16,17,18,19,20]]

然后创建一个从值到列表的映射。

代码语言:javascript
复制
theMap = concat $ map (\x -> zip x (repeat x)) lists

这会给你所需要的

代码语言:javascript
复制
> lookup 1
Just [0,1,2,3,4,5,6]

注意,输出是一个Maybe,在没有在任何列表中提供一个值的情况下。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36878340

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档