Open AIRTucha opened 6 years ago
Hey @AIRTucha ,
Could you elaborate about your use case a bit? In what kind of context would one be adding up gray scale values until they are 255?
foldWhile
seems like a substitute for recursion to me. So either this function has to beat simple recursion in its usefulness, or it provides something different from recursion that I am not yet seeing.
Hey @Chadtech, I am sorry for a long response, I was a little bit busy.
I might get you wrong, but all these functions are substitutes for recursion in some sense.
So, as I said before, there are two cases: 1) It is faster solution for
list
|> takeWhile someFunction1
|> foldl someFunction2 someInitialValue
The performance is improved by: prevention of an intermediate creation and lower number of function calls. It should also reduce a pressure on GC.
2) You need to accumulate data from the list, but you want to stop if a certain condition is achieved. For example, you have a list of buckets and you wanna fill a tank. So, you do:
type alias Litre = Float
type alias Tank =
{ level: Litre
, volume: Litre
}
add2Tank tank bucket =
let
newLevel = tank.level + bucket
in
if tank.volume > newLevel then
Just newLevel
else
Nothing
buckets: List Litre
buckets =
[ 1.5, 1.2, 2.0 ]
tank = -- { level: 4.7, volume: 5 }
buckets
|> add2Tank { level: 0.4, volume: 5 }
Of course, it can be easily done by recursion, but several times, I faced a situation when I want such a function.
Hey @AIRTucha , sorry for the delay in my reply. Heres a comparison as I see it, between using recursion and foldWhile
type alias Tank =
{ level : Float
, volume : Float
}
buckets : List Float
buckets =
[ 1.5, 1.2, 2.0 ]
tank : Tank
tank =
{ level : 0.4
, volume : 5
}
-- Recursion
fillTank : List Bucket -> Tank -> Tank
fillTank buckets tank =
case buckets of
first :: rest ->
if first + tank.level > tank.volume then
tank
else
fillTank { tank | level = tank.level + first } rest
[] ->
tank
-- foldWhile
fillTank : List Bucket -> Tank -> Tank
fillTank buckets tank =
List.Extra.foldWhile addToTank tank buckets
addToTank : Bucket -> Tank -> Maybe Tank
addToTank bucket tank =
if first + tank.level > tank.volume then
Nothing
else
Just tank
I see the recursive technique at least as good at the foldWhile technique. Here are a few disadvantages that I see in the foldWhile
technique:
0 The Maybe
in the foldWhile technique hurts readability. Someone who is seeing the code for the first time might not understand the meaning of the Maybe
, making it that much harder to grasp the purpose of the code at a glance.
1 The foldWhile
technique requires List.Extra
Great example @Chadtech. Just wanted to chime in that in addition to hurting readability, using Maybe
s in lieu of actual recursion most likely negatively affects performance.
Wait a minute, you can eliminate foldl by the exact same way, can't you?
Ok, another possible case, actually, it was one of the reasons I wrote it here. So, I was working on some kind of parser. One of the key places in my project was folding over lines, parsing of each of them a combining them together. Parsing of each next line was based on a result previous one, so if it fails it has to stop and output the successful part.
I assume that there are some other case on which the same pattern can be applied.
Anyway, it is "extra", I used to think that the main idea here is to collect and experimental features and see if people are going to use them.
List.foldlWhile function seems to be useful in two practical cases:
Accumulation of pixels in a grey scale image is a good example of the function use case.