Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.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
List 如何用惯用法编写此函数?_List_Haskell_Functional Programming_Filtering_Higher Order Functions - Fatal编程技术网

List 如何用惯用法编写此函数?

List 如何用惯用法编写此函数?,list,haskell,functional-programming,filtering,higher-order-functions,List,Haskell,Functional Programming,Filtering,Higher Order Functions,我正在寻找一个函数,该函数在列表的元素上测试谓词,为满足谓词的每个元素创建一个新的列表,并将函数仅应用于该元素 例如: someFunction :: (a -> Bool) -> (a -> a) -> [a] -> [[a]] someFunction = ... let ys = someFunction isOdd (* 2) [1..10] {- ys == [[2, 2, 3, 4, 5, ...], [1, 2,

我正在寻找一个函数,该函数在列表的元素上测试谓词,为满足谓词的每个元素创建一个新的列表,并将函数仅应用于该元素

例如:

someFunction :: (a -> Bool) -> (a -> a) -> [a] -> [[a]]
someFunction = ...

let ys = someFunction isOdd (* 2) [1..10]
    {- ys == [[2, 2, 3, 4, 5,  ...],
              [1, 2, 6, 4, 5,  ...],
              [1, 2, 3, 4, 10, ...],
              ...] -}
ys
中,除满足谓词并乘以
2的第一个元素外,第一个列表与原始列表相等。除第三个元素外,第二个列表也与原始列表相同,依此类推

通过获取满足谓词的值的索引,然后通过索引进行映射,我已经能够编写这样一个函数。但是,这似乎不是很实用,我希望看到一种更惯用的方法。

怎么样:

从以下列表开始:

[1,2,3,4]
复制列表n次,n为其大小(
:[[]]
):

拆分每个元素上的列表(或多或少是“对角的”)(
::[([]),[])]
):

过滤掉
标题所在的行。snd
不满足您的谓词

[
 ([],    [1,2,3,4]),
 ([1,2], [3,4])
]
将您的功能应用于其余头部

[
 ([],    [2,2,3,4])
 ([1,2], [6,4]),
]
将这些对连在一起

[
 [2,2,3,4],
 [1,2,6,4]
]
您可以使用手指(如a:D,阅读时将手指移动到每个项目上:D)

r
函数取
ps
“已处理元素”和
(y:ys)
“待处理元素”

如果您需要线性成本(
ps++[y]
operation do it cuadratic),请使用有效的尾部插入结构

使用
splitAt
可以编写

someFunction check f xs = map (\(a,(x:b)) -> a ++ [f x] ++ b) $
                          filter (check.head.snd)
                          [splitAt n xs | n <- [0..length xs - 1]]
最后(?)@rjanJohansen注释删除
init$
(我留下两个版本,我认为这是一个很好的例子)

避免
init$

someFunction check f xs = 
    [ a ++ [f x] ++ b | (a, (x:b)) <- zip (inits xs) (tails xs)
                      , check x]

(thx@williness)

您可以使用标准件或应安装件来组装此功能。公认的答案有正确的拉链线索。我的回答是对相关操作的一般处理,但让我在这里具体说明

我将“具有一个元素孔的列表”的类型定义如下:

data Bwd x = B0 | Bwd x :< x deriving Show
type HoleyList x = (Bwd x, [x])
其思想是,该对的第二个组件位于向后列表和向前列表之间。我可以定义将列表插回一起的函数(在泛型处理中称为
upF

注意

map snd  (selections xs) = xs 
map plug (selections xs) = map (const xs) xs
现在我们可以按照巴特克的食谱做了

selectModify :: (a -> Bool) -> (a -> a) -> [a] -> [[a]]
selectModify p f = map (plug . (id *** f)) . filter (p . snd) . selections
也就是说:通过测试过滤选择,将函数应用于聚焦的元素,然后重新插入。如果你有拉链设备,它是一个单衬里,它应该适用于任何可微函子,而不仅仅是列表!工作完成了

> selectModify ((1 ==) . (`mod` 2)) (2*) [1..10]
[[2,2,3,4,5,6,7,8,9,10]
,[1,2,6,4,5,6,7,8,9,10]
,[1,2,3,4,10,6,7,8,9,10]
,[1,2,3,4,5,6,14,8,9,10]
,[1,2,3,4,5,6,7,8,18,10]]

通过浏览这里发布的所有不错的、大多有些别致的解决方案(包括@josejuan最后一个基于
zip
的解决方案,这基本上就是我会在匆忙中使用的惯用语),我不禁感到列表缺少了真正直接的、但仍然是惯用的解决方案,即使用explicit,惰性递归——如果
someFunction
是一个标准函数,您可能会在标准库中看到这种代码。下面是一个版本(包括您还会看到的
go
worker包装):


你说的“对角线”是什么意思?让我把它展开一点。@aochagavia,你看。也许跳过复制步骤,直接压缩初始化和尾部更容易。一个遍历镜头也可以被看作是一个手指。最后一个
zip
建议基本上就是我自己快速编写的习惯用法,但我只想补充一点,您不需要
init$
部分-最后一对被
(a,(x:b))
模式自动过滤掉。@rjanJohansen我想
非穷举模式
会报告错误。很好的例子!谢谢!“desugar do表示法”不起作用,因为通常简单的
do p
e1>=\p->e2
实际上不是-而这种情况下,当
p
是一种可能失败的模式时,恰恰是它的断裂处。desugar list理解是一种使用
concatMap
的代码,而不是
do
。)
someFunction check f xs = 
    [ a ++ [f x] ++ b | (a, (x:b)) <- zip (inits xs) (tails xs)
                      , check x]
[e | p <- l, Q] = let ok p = [e | Q]
                      ok _ = []
                  in concatMap ok l
data Bwd x = B0 | Bwd x :< x deriving Show
type HoleyList x = (Bwd x, [x])
type InContext x = (HoleyList x, x)
plug :: InContext x -> [x]
plug ((B0, xs), y)      = y : xs
plug ((xz :< x, xs), y) = plug ((xz, y : xs), x)
selections :: [x] -> [InContext x]
selections = go B0 where
  go xz [] = []
  go xz (x : xs) = ((xz, xs), x) : go (xz :< x) xs
map snd  (selections xs) = xs 
map plug (selections xs) = map (const xs) xs
selectModify :: (a -> Bool) -> (a -> a) -> [a] -> [[a]]
selectModify p f = map (plug . (id *** f)) . filter (p . snd) . selections
> selectModify ((1 ==) . (`mod` 2)) (2*) [1..10]
[[2,2,3,4,5,6,7,8,9,10]
,[1,2,6,4,5,6,7,8,9,10]
,[1,2,3,4,10,6,7,8,9,10]
,[1,2,3,4,5,6,14,8,9,10]
,[1,2,3,4,5,6,7,8,18,10]]
someFunction :: (a -> Bool) -> (a -> a) -> [a] -> [[a]]
someFunction p f xs = go xs where
    go [] = []
    go (x:xs)
      | p x         = (f x : xs) : rest
      | otherwise   = rest
      where
        rest = map (x :) (go xs)