Thread overview
Is there a standard function that combines take() and popFrontExactly()
Dec 11, 2020
realhet
Dec 14, 2020
Dukc
Dec 14, 2020
realhet
December 11, 2020
Hi,

I've just made this unicode wordreplacer function working, but It seems not too nice and functional-ish.
Are there ways to make it more simple?


import std.stdio, std.range, std.algorithm, std.uni, std.utf, std.conv;

bool isWordChar(dchar ch){
    return isAlphaNum(ch) || ch=='_';
}

string replaceWords(alias fun = isWordChar)(string str, string from, string to){
    auto res = appender!string();
    auto src = str.byCodePoint;
    foreach(isWord, len; str.map!fun.group){
        auto act = src.take(len).text;
        src.popFrontExactly(len);

        res.put(isWord && act==from ? to : act);
    }
	return(res[]);
}

void main(){
    immutable str = "Type=FunctionType Type; éType Type2: Type aTypeb Type";
    str.replace("Type", "AsmType").writeln;
    str.replaceWords("Type", "AsmType").writeln;
}

Thanks in advance!
December 14, 2020
On Friday, 11 December 2020 at 19:07:23 UTC, realhet wrote:
> I've just made this unicode wordreplacer function working, but It seems not too nice and functional-ish.
> Are there ways to make it more simple?


To answer the title, yes there is:

```
foreach(isWord, len; str.map!fun.group){
   auto act = (&src).refRange.take(len).text;

   res.put(isWord && act==from ? to : act);
}
```

But personally I think it does not pay to try to be more functional than what this snippet already is. The most important thing is that the program is functional on the high level. This means avoiding globals and static variables (`pure` may help), big monolithic functions, god classes and functions which get needless info by their parameters. Being functional in the low level is secondary and not always worth it.
December 14, 2020
On Monday, 14 December 2020 at 14:16:41 UTC, Dukc wrote:
> On Friday, 11 December 2020 at 19:07:23 UTC, realhet wrote:
>> I've just made this unicode wordreplacer function working, but It seems not too nice and functional-ish.
>> Are there ways to make it more simple?
>
>
> To answer the title, yes there is:
>

Thanks for ideas!

Yesterday I ended up making this helper funct:
auto fetchFrontExactly(R)(ref R r, size_t n) if(isInputRange!R){
    auto res = r.takeExactly(n);
    r.popFrontExactly(n);
    return res;
}

Now I leaned from you: refRange and take-s ability to pop elements from a refRange.
That's what I was needed!

Now the 2 aproach looks like:

string replaceWords(alias fun = isWordChar)(string str, string from, string to){
    if(1){
        auto fetchAndReplace(Tuple!(bool, uint) p){
            auto act = refRange(&str).take(p[1]).text;
            return p[0] && act==from ? to : act;
        }
        return str.map!fun
                  .group
                  .map!fetchAndReplace
                  .join;
    }else{
        string res;
        foreach(isWord, len; str.map!fun.group){
            auto act = (&str).refRange.take(len).text;
            res ~= (isWord && act==from ? to : act);
        }
		return(res);
    }
}

They are the same thing, but the first looks nicer because it is a processing pipe with the state modifying thing extracted to a named function (so that's makes the pipe more understandable).
However in the foreach version I can have meaningful parameter names: (isWord, len) instead of a tuple.

I don't want to do functional programming just for itself. I'm just learning it, and want to understand it better. I already found a lot of good uses of it for my tasks and I still discover a lot of cool stuff.

Thanks again!