Skip to content

Conversation

@timotheecour
Copy link
Member

@timotheecour timotheecour commented Aug 17, 2018

  • needed for subsequent PR's
  • it's a useful and versatile proc that generalizes other procs

in other languages

Copy link
Member

@Araq Araq left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll accept this since I happen to know where you want to use it, but I'm not convinced strutils.countWhile is useful enough. strutils is full of stuff that I never use, yet strutils is one of the few modules that is used in every program.

while last >= 0 and s[last] in chars: dec(last)
result = substr(s, first, last)

proc countWhile*(str: string, pred : proc(a:char):bool, prefix = true): int =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: Watch the spacing around your colons.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prefix should instead be countdown=false.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And I think s instead of str is more common in the stdlib.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And I think the signature should be this, there is little you can do in this callback that receives a single char...

proc countWhile*(s: string; x: set[char]; countdown = false): int

Or maybe

template countWhileIt*(s: string; e: untyped; countdown = false): int

doAssert countWhile("abc//", a=>a == '/', prefix = false) == 2
doAssert countWhile("abcDEF", isLowerAscii) == 3

let lenS = len(str)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code looks better without the helper lenS, use s.len instead.

for i in 0..<lenS:
if not pred(str[i]): return i
else:
for i in 0..<lenS:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use a countdown loop here instead.

@dom96
Copy link
Contributor

dom96 commented Aug 17, 2018

I believe I already explained why I don't think this function should make it into the stdlib.

Just to reiterate:

  • It's incredibly specific thus unlikely to be used by many people.
  • It can be easily emulated using functions defined in parseutils or using a simple for loop.
  • I've searched a little and don't see a similar function in the stdlib of other languages. Most functional programming languages offer a filter function which would emulate the functionality of this procedure very well.

Nim actually already has a filter function but it only supports openarrays. A nice improvement would be to implement filter for strings.

@dom96 dom96 closed this Aug 17, 2018
@timotheecour
Copy link
Member Author

/cc @Araq Please re-open this PR; it's good etiquette in open source to wait for an answer from PR author before closing.

It can be easily emulated using functions defined in parseutils

In here https://github.com/nim-lang/Nim/pull/8351/files#r203705914 you mentioned parseutils.parseWhile [1] ; that doesn't work:

  • I need to allow going from either end (parseWhile doesn't, nor does anything in parseutils)
  • parseWhile allocates; countWhile doesn't
  • a set[char] is just not flexible enough, eg, there's no efficient or simple way to write countWhile("abcDEF", isLowerAscii) with parseWhile (would require precomputing a set of valid chars, which is both inefficient and unwieldy)

Yes, it can be emulated with a for loop; but that's less readable, and tricky to use, especially for the countdown (backwards) version

It's incredibly specific thus unlikely to be used by many people.

I'm using it in my projects in a number of places (as well as upcoming PR's), it simplifies code.

I've searched a little and don't see a similar function in the stdlib of other languages

I added such examples in top-level msg of this PR

Most functional programming languages offer a filter function which would emulate the functionality of this procedure very well

no, filter is completely different: countWhile terminates when condition stops being true; filter terminates at end of input. There are lots of other differences.

[1] proc parseWhile(s: string; token: var string; validChars: set[char]; start = 0): int {..}

@timotheecour timotheecour changed the title strutils.countWhile: counts while a predicate is true, starting from either end [TODO] strutils.countWhile: counts while a predicate is true, starting from either end Aug 17, 2018
@dom96
Copy link
Contributor

dom96 commented Aug 17, 2018

parseWhile allocates; countWhile doesn't

Okay, but couldn't you use skipUntil instead?

import parseutils

doAssert(skipUntil("abcDEF", {'A' .. 'Z'}) == 3)

a set[char] is just not flexible enough, eg, there's no efficient or simple way to write countWhile("abcDEF", isLowerAscii) with parseWhile (would require precomputing a set of valid chars, which is both inefficient and unwieldy)

This is not inefficient nor unwieldy: {'a' .. 'z'}.

I need to allow going from either end (parseWhile doesn't, nor does anything in parseutils)

That is a problem. Reverse the string? :)

If that's too much of a performance hit then you can implement "prefix" mode for the parseutils procs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants