简体   繁体   中英

What does the following function do? (scanl)

I really don't understand what does scanl (\\sf -> fs ) g do in this example. What is f ?

data Grid = Grid [Line]
data CellState = Dead | Alive deriving (Eq)
data Cell = Cell CellState Int deriving (Eq)
data Line = Line [Cell] Int deriving (Eq)

run :: Grid -> Int -> [Grid]
run g n = scanl (\s f -> f s) g $ replicate n playRound

playRound :: Grid -> Grid

From the documentation for scanl :

scanl is similar to foldl, but returns a list of successive reduced values from the left:

 scanl fz [x1, x2, ...] == [z, z `f` x1, (z `f` x1) `f` x2, ...] 

Note that last (scanl fz xs) == foldl fz xs .

So, scanl (\\sf -> fs ) g behaves like this:

scanl (\s f -> f s) g [x1, x2, ...] == [g, x1 g, x2 (x1 g), ...]

Since \\sf -> fs is an anonymous function which takes two arguments and applies the second to the first:

 λ> (\s f -> f s) 2 (+1)
 3
 λ> (\s f -> f s) "Hello" length
 5

Note that \\sf -> fs could be written as flip ($) .


So, specifically:

run g n = scanl (\s f -> f s) g $ replicate n playRound

Could be seen as:

run g n = [g, playRound g, playRound (playRound g), ...] -- Repeated n times.

If we look at the documentation of scanl :: (b -> a -> b) -> b -> [a] we see that:

  

scanl is similar to foldl, but returns a list of successive reduced values from the left:

 scanl fz [x1, x2, ...] == [z, z `f` x1, (z `f` x1) `f` x2, ...] 

Note that

 last (scanl fz xs) == foldl fz xs. 

So it starts with n initial value z , and each time it applies a function to z and the next element of the given list.

Here the initial value is g , and the list is replicate n playRound (which means a list of n items, each item is playRound ). The function here takes the accumulator s , and an element of the list (here always playRound ), and the outcome of fs (in this case playRound s ), is the next item in the list.

So it will produce a list:

[g, playRound g, playRound (playRound g), ...]

and the list will contain n+1 items.

Probably a more elegant approach should have been:

run :: Grid -> Int -> [Grid]
run g n = take (n+1) $ iterate playRound g

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM