As I often program in a more declarative than imperative style I miss some methods. For example:
foo := [1, 2, 3, 4, 5]
bar := foo.takeWhile |Int x->Bool| { return x < 3 }
// bar == [1, 2]
baz := foo.dropWhile |Int x->Bool| { return x < 3 }
// baz == [3, 4, 5]
takeWhile takes elements from a list while the predicates is true. dropWhile drops elements while the predicate is true and returns the rest. If you'd concatenate the result of both methods with the same predicate you'd get a copy of the original list.
Haskell has it as takeWhile and dropWhile in it's prelude, C# has it as extension methods TakeWhile and SkipWhile on IEnumerable.
Why can't you write them yourself?
As said I don't realy understand Fan's generics system. So how do I write a function that takes a list of any type and returns a list of the same type?
And how do I write a function that takes a list of any type and a mapping function from the type of the list to another type and return a list of that other type, e.g. if I want to write ... don't know, a reverse map function?
How do I write a zipWith function taking two lists and a function taking two arguments, one of the type of the first list, one of the type of the second list. The function should return a list of the type that the passed function returns.
listA := [1, 2, 3]
listB := ["a", "b", "c"]
result = zipWith(listA, listB) |Int a, String b->String| { return a.toString() + " => " + b }
// result == ["1 => a", "2 => b", "3 => c"]
alexlamslFri 21 Nov 2008
(I've replied to your message in the other thread before noticing this one.)
Unless I have mistaken, it seems that we have such functionality already:
bar := foo.findAll |Int x->Bool| { return x < 3 }
baz := foo.exclude |Int x->Bool| { return x < 3 }
Prelude> let x = [1, 2, 3, 1, 2, 3]
Prelude> takeWhile (<3) x
[1,2]
Prelude> dropWhile (<3) x
[3,1,2,3]
Result:
[1, 2, 1, 2] is not the same as [1,2]
[3, 3] is not the same as [3,1,2,3]
katoxFri 21 Nov 2008
If you'd concatenate the result of both methods with the same predicate you'd get a copy of the original list.
Helium: That's not true regarding your last post. What is the precise semantics?
heliumFri 21 Nov 2008
BTW:
Haskell: filter
Ruby: filter
Python: filter
SML/OCaml: filter
Common Lisp: filter
Scala: filter
Fan: findAll
heliumFri 21 Nov 2008
> If you'd concatenate the result of both methods with the same predicate you'd get a copy of the original list. Helium: That's not true regarding your last post. What is the precise semantics?
Huh?
Prelude> takeWhile (<3) x ++ dropWhile (<3) x
[1,2,3,1,2,3]
Precise semantics ... code?
takeWhile :: (a -> Bool) -> [a] -> [a]
takeWhile p [] = []
takeWhile p (x:xs)
| p x = x : takeWhile p xs
| otherwise = []
dropWhile :: (a -> Bool) -> [a] -> [a]
dropWhile p [] = []
dropWhile p xs@(x:xs')
| p x = dropWhile p xs'
| otherwise = xs
takeWhile returns elements from a list as long as the predicate is true. It stops at the first element for which the predicate is false in contrast to findAll which would go on till the end of the list.
dropWhile bypasses elements in a list as long as the predicate is true and then returns the remaining elements.
brianFri 21 Nov 2008
The different between takeWhile and dropWhile is that the loop terminates as soon as the function returns false. This is similar to how eachBreak terminates on a non-null return.
The way you would implement that functionality today:
index := x.findIndex |Int y->Bool| { return y < 3 }
takeWhile := x[0..index]
dropWhile := x[index..-1]
If there is agreement that those methods are useful, I don't mind adding them.
Although I'm not sure the name is consistent with other methods. I'd probably be inclined to use the following naming convention:
eachWhile // rename eachBreak for consistenty
findWhile // instead of takeWhile to be consistent with find and findAll
excludeWhile // instead of dropWhile to be consistent with exclude
As said I don't realy understand Fan's generics system. So how do I write a function that takes a list of any type and returns a list of the same type?
In general you just use Obj[] and rely on the compiler to auto-cast if necessary - like you'd program in Python. If you really want to keep reflective types you can do this:
Are eachWhile/findWhile/excludeWhile that useful? The List class is so core that we need to be very careful that what we add is really useful to all. Particularly need to work out what Fan's coding style is (ie. not overly functional...)
heliumFri 21 Nov 2008
Good point. I might be the only person that writes on this forum that would use this functionality.
andyFri 21 Nov 2008
I actually really like the xxxWhile convention - I vote eachBreak change to eachWhile. And I could see findWhile and excludeWhile being useful, but I've yet to come across a use case for them personally.
brianFri 21 Nov 2008
Yeah, now that Helium has exposed us to takeWhile and dropWhile - I'm thinking we should use the "while" naming convention instead of "break" from our previous discussion. So I propose we rename eachBreak to eachWhile. Or maybe we should rename it to findWhile and takeWhile might be findAllWhile?
Then if we decide to add findWhile and excludeWhile we'd have a consistent naming scheme.
JohnDGFri 21 Nov 2008
find suggests the wrong thing and should not be used in combination with while.
Universally, in languages and APIs that use while, it means to start from the beginning of the list and continue until some predicate evaluates to false. find universally means to search until matches are found -- skipping over non-matches. find and while are fundamentally incompatible.
find is an element collector. It collects all elements for which the predicate is true. As helium pointed out, it's usually known as filter, because it filters out stuff you don't want.
takeWhile starts at the beginning of the list and collects elements until reaching the first element for which the predicate is false. take is a specialization of takeWhile that evaluates to false after N invocations.
dropWhile starts at the beginning of the list and removes elements until reaching the first element for which the predicate is true. drop is a specialization of dropWhile that evaluates to false after N invocations.
take/drop/takeWhile/dropWhile are likely to be used only by programmers having some functional background. That said, I imagine they might be used by a wider audience in Fan, because Fan offers built-in support for immutability.
alexlamslFri 21 Nov 2008
Sincerely apology for not knowing what those Haskell calls were for. Although I'd find Brian's findIndex code to be simple and straight-forward enough.
IMHO, eachBreak --> eachWhile yes, but findAll and exclude are good as they are. If for anything, findAll --> includeAll and exclude --> excludeAll seems more precise in implying what they do.
jodastephenSat 22 Nov 2008
I consider findAll() to be a more friendly name than filter().
In my head, I would expect filter() to modify the existing list, whereas findAll() to return a new list. Perhaps the definition of method names differs based on whether you have mutable state in a language, and whether that mutable state (OO) is more important than the non-mutable state (FP).
Finally, I still consider eachBreak() to be a hack. I want it to be something we remove if we can get non-local returns working that are hard for a developer to get wrong.
Overall, I wouldn't add these take/drop/while methods and I wouldn't rename eachBreak. Instead, we should focus on finally solving construction/with-blocks/non-local returns.
brianSat 22 Nov 2008
Finally, I still consider eachBreak() to be a hack. I want it to be something we remove if we can get non-local returns working that are hard for a developer to get wrong.
I agree non-locals would be nice. But even if we had them I don't consider having a specialized iterator which terminates on a condition a "hack". In fact its has turned out to be a very useful (and used) method in the API.
I will rename eachBreak to eachWhile. Then we can evaluate over time if the others make sense. Typically I like to wait until I come across a bit of code where I need it myself - and now that I am aware of dropWhile and takeWhile I'll be keeping it in the back of my mind.
helium Fri 21 Nov 2008
As I often program in a more declarative than imperative style I miss some methods. For example:
takeWhile
takes elements from a list while the predicates istrue
.dropWhile
drops elements while the predicate is true and returns the rest. If you'd concatenate the result of both methods with the same predicate you'd get a copy of the original list.Haskell has it as
takeWhile
anddropWhile
in it's prelude, C# has it as extension methodsTakeWhile
andSkipWhile
on IEnumerable.As said I don't realy understand Fan's generics system. So how do I write a function that takes a list of any type and returns a list of the same type?
And how do I write a function that takes a list of any type and a mapping function from the type of the list to another type and return a list of that other type, e.g. if I want to write ... don't know, a reverse
map
function?How do I write a
zipWith
function taking two lists and a function taking two arguments, one of the type of the first list, one of the type of the second list. The function should return a list of the type that the passed function returns.alexlamsl Fri 21 Nov 2008
(I've replied to your message in the other thread before noticing this one.)
Unless I have mistaken, it seems that we have such functionality already:
helium Fri 21 Nov 2008
Fansh:
GHCi:
Result:
katox Fri 21 Nov 2008
Helium: That's not true regarding your last post. What is the precise semantics?
helium Fri 21 Nov 2008
BTW:
Haskell: filter
Ruby: filter
Python: filter
SML/OCaml: filter
Common Lisp: filter
Scala: filter
Fan: findAll
helium Fri 21 Nov 2008
Huh?
Precise semantics ... code?
takeWhile
returns elements from a list as long as the predicate is true. It stops at the first element for which the predicate is false in contrast tofindAll
which would go on till the end of the list.dropWhile
bypasses elements in a list as long as the predicate is true and then returns the remaining elements.brian Fri 21 Nov 2008
The different between takeWhile and dropWhile is that the loop terminates as soon as the function returns false. This is similar to how eachBreak terminates on a non-null return.
The way you would implement that functionality today:
If there is agreement that those methods are useful, I don't mind adding them.
Although I'm not sure the name is consistent with other methods. I'd probably be inclined to use the following naming convention:
In general you just use
Obj[]
and rely on the compiler to auto-cast if necessary - like you'd program in Python. If you really want to keep reflective types you can do this:jodastephen Fri 21 Nov 2008
Are eachWhile/findWhile/excludeWhile that useful? The List class is so core that we need to be very careful that what we add is really useful to all. Particularly need to work out what Fan's coding style is (ie. not overly functional...)
helium Fri 21 Nov 2008
Good point. I might be the only person that writes on this forum that would use this functionality.
andy Fri 21 Nov 2008
I actually really like the
xxxWhile
convention - I voteeachBreak
change toeachWhile
. And I could seefindWhile
andexcludeWhile
being useful, but I've yet to come across a use case for them personally.brian Fri 21 Nov 2008
Yeah, now that Helium has exposed us to takeWhile and dropWhile - I'm thinking we should use the "while" naming convention instead of "break" from our previous discussion. So I propose we rename
eachBreak
toeachWhile
. Or maybe we should rename it tofindWhile
andtakeWhile
might befindAllWhile
?Then if we decide to add
findWhile
andexcludeWhile
we'd have a consistent naming scheme.JohnDG Fri 21 Nov 2008
find
suggests the wrong thing and should not be used in combination withwhile
.Universally, in languages and APIs that use
while
, it means to start from the beginning of the list and continue until some predicate evaluates to false.find
universally means to search until matches are found -- skipping over non-matches.find
andwhile
are fundamentally incompatible.find
is an element collector. It collects all elements for which the predicate is true. As helium pointed out, it's usually known asfilter
, because it filters out stuff you don't want.takeWhile
starts at the beginning of the list and collects elements until reaching the first element for which the predicate is false.take
is a specialization oftakeWhile
that evaluates to false after N invocations.dropWhile
starts at the beginning of the list and removes elements until reaching the first element for which the predicate is true.drop
is a specialization ofdropWhile
that evaluates to false after N invocations.take/drop/takeWhile/dropWhile are likely to be used only by programmers having some functional background. That said, I imagine they might be used by a wider audience in Fan, because Fan offers built-in support for immutability.
alexlamsl Fri 21 Nov 2008
Sincerely apology for not knowing what those Haskell calls were for. Although I'd find Brian's
findIndex
code to be simple and straight-forward enough.IMHO,
eachBreak
-->eachWhile
yes, butfindAll
andexclude
are good as they are. If for anything,findAll
-->includeAll
andexclude
-->excludeAll
seems more precise in implying what they do.jodastephen Sat 22 Nov 2008
I consider findAll() to be a more friendly name than filter().
In my head, I would expect filter() to modify the existing list, whereas findAll() to return a new list. Perhaps the definition of method names differs based on whether you have mutable state in a language, and whether that mutable state (OO) is more important than the non-mutable state (FP).
Finally, I still consider eachBreak() to be a hack. I want it to be something we remove if we can get non-local returns working that are hard for a developer to get wrong.
Overall, I wouldn't add these take/drop/while methods and I wouldn't rename eachBreak. Instead, we should focus on finally solving construction/with-blocks/non-local returns.
brian Sat 22 Nov 2008
I agree non-locals would be nice. But even if we had them I don't consider having a specialized iterator which terminates on a condition a "hack". In fact its has turned out to be a very useful (and used) method in the API.
I will rename
eachBreak
toeachWhile
. Then we can evaluate over time if the others make sense. Typically I like to wait until I come across a bit of code where I need it myself - and now that I am aware of dropWhile and takeWhile I'll be keeping it in the back of my mind.