J. *_*bal 6 haskell functional-programming list-comprehension list
我决定学习Haskell并学习以更实用的方式思考,所以我试图解决非常简单的练习,试图在这个范例中使用一个好的方法.
我想在Haskell中实现这个简单的练习:
Input: [2, 4, 1, 1, 2]
Output: [True, True, False, False, False, False, True, False, True, True]
Run Code Online (Sandbox Code Playgroud)
所以,在元素Input
列表将下降到是False
在
Output
列表中,奇数元素将是True
; 每个重复的次数与Input
列表中的值相同.
遍历Input
列表,如果我 ᵗʰ项目是在一对位置上,附加到输出True
我倍Output
; 如果
我 ᵗʰ产品在奇数位置,追加False
我倍到Output
列表中.
这似乎是一个非常简单的问题,而且确实如此.但对我来说,没有任何函数式编程背景,我不知道如何在Haskell中表达它.
我试图通过在列表理解中使用λ函数来跟踪当前索引.
row :: [Integer] -> [Bool]
row xs = [ (last $ zipWith (\i x -> x) [1..] [0..i]) `mod` 2 == 0
| j <- xs, i <- [0..j-1] ]
Run Code Online (Sandbox Code Playgroud)
但是我不了解它的行为,所以我最终选择使用它findIndices
作为一个快速的选择:
row :: [Integer] -> [Bool]
row xs = [ (head $ findIndices (==j) (xs)) `mod` 2 == 0
| j <- xs, i <- [0..j-1] ]
Run Code Online (Sandbox Code Playgroud)
使用这最后一种方法似乎没问题:
> let xs = [ 1, 4, 3, 2 ]
> print $ row xs
[True,False,False,False,False,True,True,True,False,False]
Run Code Online (Sandbox Code Playgroud)
但问题没有解决,因为这些项目不一定是唯一的:
> let xs = [ 2, 2, 4, 3]
> print $ row xs
[True,True,True,True,True,True,True,True,False,False,False]
Run Code Online (Sandbox Code Playgroud)
因为head findIndices
只给出了第一次出现.(虽然我认为,如果有效,那不是解决这个问题的有效方法.)
如何以Haskellian方式实现我正在寻找的结果?
Dan*_*her 11
您希望将输入列表中的每个元素转换Bool
为与元素所示的数量相等的序列,如果输入列表中的数字索引是偶数,并且索引是奇数,则需要Bool
be .True
False
为此,您不需要索引,最好避免使用 - 这样可以提供更简单且通常更高效的代码.关键是该值交替出现,它具有周期性模式.为了构建这样的周期性模式,Prelude提供了有用的
cycle :: [a] -> [a]
Prelude> take 10 $ cycle [1,2,3]
[1,2,3,1,2,3,1,2,3,1]
Prelude> take 10 $ cycle [True,False]
[True,False,True,False,True,False,True,False,True,False]
Run Code Online (Sandbox Code Playgroud)
整洁,这正是我们所需要的.
现在,我们可以将输入列表的每个元素与相应的配对Bool
:
[ 2, 2, 4, 3]
[True,False,True,False,...
Run Code Online (Sandbox Code Playgroud)
我们可以zip
用来生成对,[(2,True), (2,False), ...]
然后使用一个函数将该对转换为适当的Bool
s 序列.
但是这种模式非常普遍,我们有一个特殊的高阶函数,zipWith
.
因此,如果列表元素的类型是Int
,我们可以写
row :: [Int] -> [Bool]
row xs = concat $ zipWith replicate xs (cycle [True,False])
Run Code Online (Sandbox Code Playgroud)
对于类型Integer
,我们不能用replicate
,但我们可以用genericReplicate
从Data.List
.