Re: QuickSort on ranges

2020-10-18 Thread jerome via Digitalmars-d-learn

I posted some sum-up on my github.

https://preview.tinyurl.com/y6sprdbq




Re: QuickSort on ranges

2020-10-04 Thread Steven Schveighoffer via Digitalmars-d-learn

On 10/4/20 6:50 AM, jerome wrote:

Thanks you very much Ali,

I will try to wrap my head around your inputs, and get a better 
understanding of ranges in the process. I feel there is a lot of power 
in D ranges, and like the hammer of Thor, I am not worthy yet :)




Just to elaborate a bit further: Templates work by pattern matching. 
When you say


quickSort(T)(T[] r)

You are saying, match the parameter T[] to what is passed, and if it's a 
match, set T to the part of the parameter that matches. Therefore:


int[] => T = int
ubyte[] => T = ubyte

But if you leave off the array brackets:

quickSort(T)(T r)

Now T matches *any type* that you pass in, including ranges. Most range 
functions use templates because there is no supertype for ranges. They 
are checked by trying to compile the range primitives on them.


How you do more advanced checks other than pattern matching, is to use a 
template constraint, as Ali suggests.


In fact, since you are just using std.algorithm.pivotPartition, you can 
just look at the constraints it uses:


if (isRandomAccessRange!Range && hasLength!Range && hasSlicing!Range && 
hasAssignableElements!Range)


-Steve


Re: QuickSort on ranges

2020-10-04 Thread jerome via Digitalmars-d-learn

Thanks you very much Ali,

I will try to wrap my head around your inputs, and get a better 
understanding of ranges in the process. I feel there is a lot of 
power in D ranges, and like the hammer of Thor, I am not worthy 
yet :)




Re: QuickSort on ranges

2020-09-12 Thread Ali Çehreli via Digitalmars-d-learn

On 9/12/20 11:25 AM, jerome wrote:

> 
> import std.stdio : writeln;
> import std.algorithm.sorting;
>
> pure void quickSort(T) (T[] r)
> {
>if (r.length > 1)
>{
>  size_t p = pivotPartition(r, r.length-1);  //r[$-1] is swapped 
to r[p]

>
>  quickSort( r[ 0..p ] );
>  quickSort( r[ p+1..$ ] );
>}
> }
>
> void main()
> {
>int[] arr = [9,7, 4 , 8, 5, 3, 1];
>quickSort!(int)(arr);

  // No need to specify int there because it's deduced from
  // the parameter. Pretty cool: :)
  quickSort(arr);

>writeln("arr : ", arr );
>
> }
> 
>
> I spent some time understanding "ranges", but at the end I am surprised
> I didn't use them. At the beginning I wrote something like quickSort(
> Range r ) and tried randomaccessrange etc but I didn't manage to make it
> work.

Agreed. The most common range type is InputRange and most algorithms 
don't require more than that. Combined with slices being the most common 
RandomAccessRange, it's not obvious why one needs to write algorithms 
that require RandomAccessRange.


So, your algorithm is very useful already but as you said, it can't work 
with all RandomAccessRanges:


  import std.range;
  auto arr2 = iota(5).array;
  quickSort(chain(arr, arr2));// <-- Compilation error

chain() is a very smart algorithm that return a range type that can be a 
RandomAccessRange if all the ranges given to it are RandomAccessRanges. 
(Pretty awesome and very practical that we can write ranges like chain() 
in D!)


So, to make your algorithm with any RandomAccessRange, we need to change 
it like this:


pure void quickSort(R) (R r)// <-- The only change

Now the quickSort(chain(arr, arr2)) expression can be compiled and the 
result is awesome too:


  // Wow! Your quickSort operated on the elements of two
  // separate ranges! :)
  writeln(arr);
  writeln(arr2);

Optionally, you can put a template constraint on your algorithm to 
communicate the fact that it can only work with RandomAccessRanges:


import std.range : isRandomAccessRange;

pure void quickSort(R) (R r)
if (isRandomAccessRange!R)// <-- Here
{
  // ...
}

Doing that moves potential compilation errors from your algorithm to the 
caller. For example, if they call your algorithm with int[string], they 
will get a compilation error saying "you can't call this function with 
int[string]".


Ali



QuickSort on ranges

2020-09-12 Thread jerome via Digitalmars-d-learn
Hi fellow coders, I spent a couple of hours to implement a 
working, basic, quicksort. Practicing D. It finally boils down to 
that (intent to use the std, not to rewrite swap, etc):



import std.stdio : writeln;
import std.algorithm.sorting;

pure void quickSort(T) (T[] r)
{
  if (r.length > 1)
  {
size_t p = pivotPartition(r, r.length-1);  //r[$-1] is 
swapped to r[p]


    quickSort( r[ 0..p ] );
    quickSort( r[ p+1..$ ] );
  }
}

void main()
{
  int[] arr = [9,7, 4 , 8, 5, 3, 1];
  quickSort!(int)(arr);
  writeln("arr : ", arr );

}


I spent some time understanding "ranges", but at the end I am 
surprised I didn't use them. At the beginning I wrote something 
like quickSort( Range r ) and tried randomaccessrange etc but I 
didn't manage to make it work.


My question is, is there a way to write this with "ranges" as the 
argument, or does this concept of slices with the [] notation 
takes precedence somehow on the concept of ranges, in this 
particular case?


2) how would YOU write it? Using std or not.

3) any comment/code correction welcome, I am learning :)

cheers
J



Re: Quicksort Variants

2014-07-09 Thread Nordlöw

On Tuesday, 8 July 2014 at 20:50:01 UTC, Nordlöw wrote:

Also related: 
http://forum.dlang.org/thread/eaxcfzlvsakeucwpx...@forum.dlang.org#post-mailman.2809.1355844427.5162.digitalmars-d:40puremagic.com


Re: Quicksort Variants

2014-07-09 Thread Nordlöw

On Tuesday, 8 July 2014 at 20:50:01 UTC, Nordlöw wrote:
I recall that Python's default sorting algorithm is related to 
this, right?


https://en.wikipedia.org/wiki/Timsort


Quicksort Variants

2014-07-08 Thread Nordlöw

After having read

http://togototo.wordpress.com/2014/06/20/the-magic-forest-problem-revisited-rehabilitating-java-with-the-aid-of-d/

I stared at

forest_t[] quickSort(forest_t[] fors) pure nothrow {
  if (fors.length >= 2) {
auto parts = partition3!(forLessThan)(fors, fors[$ / 2]);
parts[0].quickSort;
parts[2].quickSort;
  }
  return fors;
}

for a while. Could somebody explain why this gave such a speed 
boost? To my knowledge it is an optimization which gives extra 
speedup when fors is already partially sorted right?


Are there any plans to merge this optimization into existing or 
new sorting algorithms in Phobos?


I recall that Python's default sorting algorithm is related to 
this, right?


Re: Implementing Haskell's Type-Level Quicksort in D

2014-02-14 Thread Philippe Sigaud
On Fri, Feb 14, 2014 at 3:24 PM, bearophile  wrote:
> Meta:
>
>
>> While it is heavier than Haskell's syntax, I have been consistently and
>> pleasantly surprised by how powerful D's template pattern matching is (bugs
>> notwithstanding). I wonder how well-known this is outside this mailing
>> list...

Well, I have a tutorial, but I admit it being somewhat incomplete and
now partially out of date (2012).

> I keep reading blog posts that use Haskell and present supposed "marvels",
> using very complex things, that can be routinely done in D, and with less
> complexity for the brain of the programer, often leading to faster code and
> equally safe :-) So while I like several parts of Haskell, it's sometimes
> over-hyped (while D is nearly invisible).

Same here, same here! But you have to admit some of their examples are
pretty damn elegant :)

I remember doing some Haskell -> D translation (a bit like what Meta
is doing), making it work, doing the happy-happy dance, and then
suddenly realizing I could do the same compile-time computation in one
line of D ;)


Re: Implementing Haskell's Type-Level Quicksort in D

2014-02-14 Thread bearophile

Meta:

While it is heavier than Haskell's syntax, I have been 
consistently and pleasantly surprised by how powerful D's 
template pattern matching is (bugs notwithstanding). I wonder 
how well-known this is outside this mailing list...


I keep reading blog posts that use Haskell and present supposed 
"marvels", using very complex things, that can be routinely done 
in D, and with less complexity for the brain of the programer, 
often leading to faster code and equally safe :-) So while I like 
several parts of Haskell, it's sometimes over-hyped (while D is 
nearly invisible).


Bye,
bearophile


Re: Implementing Haskell's Type-Level Quicksort in D

2014-02-14 Thread Meta
On Friday, 14 February 2014 at 06:05:08 UTC, Philippe Sigaud 
wrote:

`alias` is just a bit of syntax sugar, it does not (at least for
2.064) have the same power than fully defining a template and 
the `is(...)` expression.


Right. What I was saying, however, is it is strange to me that 
this code will compile:


alias numPred(N: Succ!a, a) = a;

struct Number(a)
if (is(a == Zero) || is(a == Succ!x, x))
{}

enum numValue(N: Number!Zero) = 0;
enum numValue(N: Number!x, x) = numValue!(Number!(numPred!x)) + 1;

assert(numValue!(Number!Zero) == 0);
assert(numValue!(Number!Four) == 4);


While this code won't:

struct Nil{}
struct Cons(a, b) {}

alias list1 = Cons!(Three, Cons!(Two, Cons!(Four, Cons!(One, 
Nil;


alias numlHead(L: Cons!(a, b), a, b) = a;

alias numlTail(L: Cons!(a, b), a, b) = b;

assert(is(numlHead!list1 == Three));


Since list1 is a roughly similar construction to 
Number!(Succ!(Succ!(Succ!(Succ!Zero, it is surprising to me 
that the template matching system can correctly destructure the 
latter, while not the former. This is obviously a bug, I'm just 
surprised that it exists.


So yes, D does not have Haskell nice syntax for pattern 
matching. You can do some pattern matching using templates,

but it tends to be a bit heavier than ML/F#/Haskell.


While it is heavier than Haskell's syntax, I have been 
consistently and pleasantly surprised by how powerful D's 
template pattern matching is (bugs notwithstanding). I wonder how 
well-known this is outside this mailing list...


(Some would say that at least D does not force you to encode 
numbers as succ/zero list, since you can use numbers directly 
as template args, but that's another story).


Sure, but I want to stay as close to the original Haskell as 
possible (and Peano Numbers are pretty damn cool anyway).


Re: Implementing Haskell's Type-Level Quicksort in D

2014-02-14 Thread bearophile

Philippe Sigaud:

So yes, D does not have Haskell nice syntax for pattern 
matching.


I'd like some of such syntax for templates (and a little 
different syntax added to match structs inside switch statements: 
https://d.puremagic.com/issues/show_bug.cgi?id=596 ).


Bye,
bearophile


Re: Implementing Haskell's Type-Level Quicksort in D

2014-02-13 Thread Philippe Sigaud
On Fri, Feb 14, 2014 at 3:54 AM, Meta  wrote:

> It seems strange that it would choke now, as Cons is a struct. Therefore,
> Cons!(Three, ...) should create a new type, and `L: Cons!(a, b), a, b`
> shouldn't be any trouble to destructure into two types, `Three` and
> `Cons!(Two, ...)`. It had no problem handling the Succ and Number struct
> templates I defined.

`alias` is just a bit of syntax sugar, it does not (at least for
2.064) have the same power than fully defining a template and the
`is(...)` expression.

So yes, D does not have Haskell nice syntax for pattern matching. You
can do some pattern matching using templates, but it tends to be a bit
heavier than ML/F#/Haskell.

(Some would say that at least D does not force you to encode numbers
as succ/zero list, since you can use numbers directly as template
args, but that's another story).


Re: Implementing Haskell's Type-Level Quicksort in D

2014-02-13 Thread Meta

On Friday, 14 February 2014 at 02:41:12 UTC, bearophile wrote:

Meta:

alias list1 = Cons!(Three, Cons!(Two, Cons!(Four, Cons!(One, 
Nil;


alias numlHead(L: Cons!(a, b), a, b) = a;

alias numlTail(L: Cons!(a, b), a, b) = b;


But the compiler is complaining loudly about a mismatch:

/d43/f234.d(39): Error: template instance numlHead!(list1) 
does not match template declaration numlHead(L : Cons!(a, b), 
a, b)


See a recent thread of mine:
http://forum.dlang.org/thread/vlwgufdlpjgewpnnh...@forum.dlang.org

Currently I think you have to accept types and aliases with a 
regular template syntax, and verify the types and kinds with 
template constraints. Something like (untested):


template numlTail(C) if (TemplateOf!(C, Cons)) {
alias numlTail = TemplateArgsOf!(C)[1];
}

Bye,
bearophile


It seems strange that it would choke now, as Cons is a struct. 
Therefore, Cons!(Three, ...) should create a new type, and `L: 
Cons!(a, b), a, b` shouldn't be any trouble to destructure into 
two types, `Three` and `Cons!(Two, ...)`. It had no problem 
handling the Succ and Number struct templates I defined.


Re: Implementing Haskell's Type-Level Quicksort in D

2014-02-13 Thread bearophile

Meta:

alias list1 = Cons!(Three, Cons!(Two, Cons!(Four, Cons!(One, 
Nil;


alias numlHead(L: Cons!(a, b), a, b) = a;

alias numlTail(L: Cons!(a, b), a, b) = b;


But the compiler is complaining loudly about a mismatch:

/d43/f234.d(39): Error: template instance numlHead!(list1) does 
not match template declaration numlHead(L : Cons!(a, b), a, b)


See a recent thread of mine:
http://forum.dlang.org/thread/vlwgufdlpjgewpnnh...@forum.dlang.org

Currently I think you have to accept types and aliases with a 
regular template syntax, and verify the types and kinds with 
template constraints. Something like (untested):


template numlTail(C) if (TemplateOf!(C, Cons)) {
alias numlTail = TemplateArgsOf!(C)[1];
}

Bye,
bearophile


Re: Implementing Haskell's Type-Level Quicksort in D

2014-02-13 Thread Meta
Coming back to this after a few days. I got a bit farther, but 
I'm running into trouble with the template args pattern matching. 
I'd like to turn this code:


 list1 :: Cons Three (Cons Two (Cons Four (Cons One Nil)))
 list1 = undefined

 numlHead :: Cons a b -> a
 numlHead = const undefined

 numlTail :: Cons a b -> b
 numlTail = const undefined'


Into this D code:

alias list1 = Cons!(Three, Cons!(Two, Cons!(Four, Cons!(One, 
Nil;


alias numlHead(L: Cons!(a, b), a, b) = a;

alias numlTail(L: Cons!(a, b), a, b) = b;


But the compiler is complaining loudly about a mismatch:

/d43/f234.d(39): Error: template instance numlHead!(list1) does 
not match template declaration numlHead(L : Cons!(a, b), a, b)


Re: Implementing Haskell's Type-Level Quicksort in D

2014-02-11 Thread bearophile

alias One = Typedef!(Succ!Zero);
alias Two = Typedef!(Succ!One);
alias Three = Typedef!(Succ!Two);
alias Four = Typedef!(Succ!Three);


Note that you need a "cookie" for those Typedefs, otherwise 
they are not useful.


They are different types, so my comment is wrong :-) I don't 
understand why you have used Typedef there.


Bye,
bearophile


Re: Implementing Haskell's Type-Level Quicksort in D

2014-02-11 Thread Meta
On Tuesday, 11 February 2014 at 19:13:01 UTC, Philippe Sigaud 
wrote:
On Mon, Feb 10, 2014 at 6:12 PM, Meta  
wrote:

I'm trying to write a D implementation of Haskell's "type level
quicksort"[0], but I'm already running into problems with
std.typecons.Typedef. I have tried to translate this Haskell 
code:



alias One = Typedef!(Succ!Zero);
alias Two = Typedef!(Succ!One);
alias Three = Typedef!(Succ!Two);
alias Four = Typedef!(Succ!Three);


Did you try just using:

alias One = Succ!Zero;
alias Two = Succ!One;
alias Three = Succ!Two;
alias Four = Succ!Three;

?

I remember having fun implementing type-level addition and
multiplication using D and this Peano construct, so Quicksort is
probably possible.


I have tried once before only semi-seriously, and using just a 
bare alias was my initial strategy. It didn't work for some 
reason, and I can't really remember why. Maybe I'll give it 
another try and just drop the Typedef.


Re: Implementing Haskell's Type-Level Quicksort in D

2014-02-11 Thread Philippe Sigaud
On Mon, Feb 10, 2014 at 6:12 PM, Meta  wrote:
> I'm trying to write a D implementation of Haskell's "type level
> quicksort"[0], but I'm already running into problems with
> std.typecons.Typedef. I have tried to translate this Haskell code:

> alias One = Typedef!(Succ!Zero);
> alias Two = Typedef!(Succ!One);
> alias Three = Typedef!(Succ!Two);
> alias Four = Typedef!(Succ!Three);

Did you try just using:

alias One = Succ!Zero;
alias Two = Succ!One;
alias Three = Succ!Two;
alias Four = Succ!Three;

?

I remember having fun implementing type-level addition and
multiplication using D and this Peano construct, so Quicksort is
probably possible.


Re: Implementing Haskell's Type-Level Quicksort in D

2014-02-11 Thread bearophile
Note that you need a "cookie" for those Typedefs, otherwise 
they are not useful. Unless this gets implemented:

http://d.puremagic.com/issues/show_bug.cgi?id=12100


See also:
http://d.puremagic.com/issues/show_bug.cgi?id=11828

Bye,
bearophile


Re: Implementing Haskell's Type-Level Quicksort in D

2014-02-11 Thread bearophile

Meta:


alias One = Typedef!(Succ!Zero);
alias Two = Typedef!(Succ!One);
alias Three = Typedef!(Succ!Two);
alias Four = Typedef!(Succ!Three);


Note that you need a "cookie" for those Typedefs, otherwise they 
are not useful. Unless this gets implemented:

http://d.puremagic.com/issues/show_bug.cgi?id=12100

Bye,
bearophile


Re: Implementing Haskell's Type-Level Quicksort in D

2014-02-11 Thread Stanislav Blinov

On Monday, 10 February 2014 at 17:12:11 UTC, Meta wrote:

I tried defining a static opCall in the Zero struct that 
doesn't take any arguments, but that didn't make a difference. 
I'm guessing this is a bug with Typedef, but does anyone have 
an idea of where that bug might be?


I would say it's not Typedef's fault, but std.typecons.Proxy's 
one. It has issues forwarding through opCall and opDispatch:


https://d.puremagic.com/issues/show_bug.cgi?id=11947

I'm currently working on a fix:

https://github.com/D-Programming-Language/phobos/pull/1914

Looks like a case for static opCall should also be covered.


Implementing Haskell's Type-Level Quicksort in D

2014-02-11 Thread Meta
I'm trying to write a D implementation of Haskell's "type level 
quicksort"[0], but I'm already running into problems with 
std.typecons.Typedef. I have tried to translate this Haskell code:


 data Zero
 data Succ a

 -- booleans
 data True
 data False

 -- lists
 data Nil
 data Cons a b

 -- shortcuts
 type One   = Succ Zero
 type Two   = Succ One
 type Three = Succ Two
 type Four  = Succ Three



To this code in D:

import std.typecons;

struct Zero {}
struct Succ(a) {}

struct True  {}
struct False {}

struct Nil {}
struct Cons(a, b) {}

alias One = Typedef!(Succ!Zero);
alias Two = Typedef!(Succ!One);
alias Three = Typedef!(Succ!Two);
alias Four = Typedef!(Succ!Three);


void main()
{
auto test = Four();
}

But I'm getting a compiler error when actually trying to 
construct a Four:


Error: template std.typecons.Typedef!(Succ!(Zero), 
Succ()).Typedef.Proxy!(Typedef_payload).opCall does not match any 
function template declaration.


Candidates are:
std.typecons.Typedef!(Succ!(Zero), 
Succ()).Typedef.Proxy!(Typedef_payload).opCall(this X, 
Args...)(auto ref Args args)




I tried defining a static opCall in the Zero struct that doesn't 
take any arguments, but that didn't make a difference. I'm 
guessing this is a bug with Typedef, but does anyone have an idea 
of where that bug might be?





1. 
http://www.haskell.org/haskellwiki/Type_arithmetic#An_Advanced_Example_:_Type-Level_Quicksort


Re: Phobos orthogonality [Was: Re: quickSort]

2011-09-14 Thread Jonathan M Davis
On Wednesday, September 14, 2011 14:36 bearophile wrote:
> Jonathan M Davis:
> > So, basically, you just want to shorten your code by wrapping array(func)
> > in a afunc function, and you think that this happens enough with map and
> > filter enough to merit putting these functions into Phobos.
> 
> There is also the point 3) that you have not seen, plus the notes about
> Haskell Prelude design.

I did see it. I read your entire post, and I don't see anything that IMHO 
justifies adding amap or afilter.

Yes, I can see why you would want to have and use amap and afilter. They 
aren't worthless. But they just don't add enough value to be worth adding to 
Phobos. And I'd be very surprised if Andrei disagreed with me based on what 
he's said about similar stuff. It was an uphill battle just to get him to 
allow drop to be added to std.range, and that actually allows code to be 
written in a different style, whereas amap and afilter pretty much just reduce 
the number of characters that a particular statement requires. Yes, the 
resulting code may look cleaner, but that's it. There's no real functional 
difference in the resulting code. It just doesn't add enough value to make it 
into Phobos.

- Jonathan M Davis


Re: Phobos orthogonality [Was: Re: quickSort]

2011-09-14 Thread bearophile
Jonathan M Davis:

> So, basically, you just want to shorten your code by wrapping array(func) in 
> a 
> afunc function, and you think that this happens enough with map and filter 
> enough to merit putting these functions into Phobos.

There is also the point 3) that you have not seen, plus the notes about Haskell 
Prelude design.

Bye,
bearophile


Re: Phobos orthogonality [Was: Re: quickSort]

2011-09-14 Thread Jonathan M Davis
On Wednesday, September 14, 2011 07:46:37 bearophile wrote:
> Jonathan M Davis:
> > What would that gain you over passing the result of map or filter to
> > std.array.array?
> 
> 1) The code gets shorter
> 2) The code gets a bit less noisy, because () add noise.
> 3) You use a single function instead of two, so you reduce the number of
> chunks your brain has to manage. A human brain is able to manage a very
> limited number of chunks at the same time (about 7). An expert programmer
> is able to merge array(map()) into a single chunk, but this requires a bit
> of training and time. 4) Maybe you are able to reduce the abstraction
> penalty for the compiler, reducing the amount of code compiled. (But this
> probably will not happen because amap will probably be just implemented
> with an array(map()) to reduce library code and time to write to write it).
> 5) The lazy result of map is quite useful. But in a large amount of
> situations in D you can't use a lazy result, you need an array (this is not
> true in Haskell). So in practice about half the time I need a map, I have
> to apply array() on it. So amap is a very  common pattern in D. 6) In
> std.parallelism there is already an map/amap pair:
> http://www.d-programming-language.org/phobos/std_parallelism.html#amap
> So for the D programmer it's not a significant burden to have the same
> functions in std.algorithm, with the same names and same purposes.
> 
> Orthogonality is overrated in Phobos. If you take a look at functional
> languages where the use of higher order functions is common, like Haskell,
> you see standard functions that are the composition of common functions.
> Haskell designers have a large experience on the usage of higher order
> functions. This is the Haskell Prelude (similar to the D object module):
> 
> http://www.haskell.org/onlinereport/standard-prelude.html
> 
> As example it contains both map and concatMap (concatMap is absent in Phobos
> still, but it will be useful to have).
> 
> The definition of concatMap is just:
> 
> concatMap :: (a -> [b]) -> [a] -> [b]
> concatMap f = concat . map f
> 
> In practice in Haskell you are allowed to write concatMap just like this:
> 
> concatMap = concat.map
> 
> This means concatMap is just using three functions, concat, map and dot
> (that is the composition function). Do you know why such simple function is
> included in the Prelude, despite it essentially saves just one character
> (the dot)? Because using a concat on the result of map is a very common
> pattern in Haskell code. So packing them in a single name allows the mind
> of the programmer to think of it as a single entity, and allows a bit
> higher thinking while you program.
> 
> This is why I think amap/afilter are worth adding to Phobos. I did have them
> in my dlibs1 and I have used them many times.

So, basically, you just want to shorten your code by wrapping array(func) in a 
afunc function, and you think that this happens enough with map and filter 
enough to merit putting these functions into Phobos. Yeah, I don't see that 
happening. It's not impossible, but there are a number of functions in Phobos 
which return lazy ranges. It's not at all reasonable to have duplicate 
versions of them all just to shorten a bit of code. And if anything, Andrei 
has been looking at heightening the bar for how much a function has to add to 
make it into std.algorithm or std.range. He feels that there's arguably too 
much duplication already. And when all a function does is making so that 
you're doing afunc(r) instead of array(func(r)), there's no way that that's 
getting in.

- Jonathan M Davis


Phobos orthogonality [Was: Re: quickSort]

2011-09-14 Thread bearophile
Jonathan M Davis:

> What would that gain you over passing the result of map or filter to 
> std.array.array?

1) The code gets shorter
2) The code gets a bit less noisy, because () add noise.
3) You use a single function instead of two, so you reduce the number of chunks 
your brain has to manage. A human brain is able to manage a very limited number 
of chunks at the same time (about 7). An expert programmer is able to merge 
array(map()) into a single chunk, but this requires a bit of training and time.
4) Maybe you are able to reduce the abstraction penalty for the compiler, 
reducing the amount of code compiled. (But this probably will not happen 
because amap will probably be just implemented with an array(map()) to reduce 
library code and time to write to write it).
5) The lazy result of map is quite useful. But in a large amount of situations 
in D you can't use a lazy result, you need an array (this is not true in 
Haskell). So in practice about half the time I need a map, I have to apply 
array() on it. So amap is a very  common pattern in D.
6) In std.parallelism there is already an map/amap pair:
http://www.d-programming-language.org/phobos/std_parallelism.html#amap
So for the D programmer it's not a significant burden to have the same 
functions in std.algorithm, with the same names and same purposes.

Orthogonality is overrated in Phobos. If you take a look at functional 
languages where the use of higher order functions is common, like Haskell, you 
see standard functions that are the composition of common functions. Haskell 
designers have a large experience on the usage of higher order functions. This 
is the Haskell Prelude (similar to the D object module):

http://www.haskell.org/onlinereport/standard-prelude.html

As example it contains both map and concatMap (concatMap is absent in Phobos 
still, but it will be useful to have). 

The definition of concatMap is just:

concatMap :: (a -> [b]) -> [a] -> [b]
concatMap f = concat . map f

In practice in Haskell you are allowed to write concatMap just like this:

concatMap = concat.map

This means concatMap is just using three functions, concat, map and dot (that 
is the composition function). Do you know why such simple function is included 
in the Prelude, despite it essentially saves just one character (the dot)? 
Because using a concat on the result of map is a very common pattern in Haskell 
code. So packing them in a single name allows the mind of the programmer to 
think of it as a single entity, and allows a bit higher thinking while you 
program.

This is why I think amap/afilter are worth adding to Phobos. I did have them in 
my dlibs1 and I have used them many times.

Bye,
bearophile


Re: quickSort

2011-09-14 Thread Jonathan M Davis
On Wednesday, September 14, 2011 06:09:52 bearophile wrote:
> %u:
> > i have qustion why filter can't return int[]
> 
> Because a lazy filter is handy, you often don't need a real array result, a
> lazy sequence is enough. A lazy sequence avoids the memory allocation of
> the output array. In D programs often the slowest parts are the memory
> allocations. On the other hand I have asked to add amap/afilter functions
> that return arrays. Andrei has not answered about this yet.

What would that gain you over passing the result of map or filter to 
std.array.array?

- Jonathan M Davis


Re: quickSort

2011-09-14 Thread bearophile
%u:

> i have qustion why filter can't return int[]

Because a lazy filter is handy, you often don't need a real array result, a 
lazy sequence is enough. A lazy sequence avoids the memory allocation of the 
output array. In D programs often the slowest parts are the memory allocations.
On the other hand I have asked to add amap/afilter functions that return 
arrays. Andrei has not answered about this yet.

Bye,
bearophile


Re: quickSort

2011-09-13 Thread Jonathan M Davis
On Wednesday, September 14, 2011 05:43:37 %u wrote:
> i have qustion why filter can't return int[]
> and if lambda return  the last Expression without return keyword it would
> much cleaner

filter can't return int[]. filter does not alter the original array. It returns 
a new range with only the elements which match the predicate. For it to return 
int[], it would have to allocate a new array, and that would be inefficient. 
Instead, it returns a new range which wraps the original array. If you want to 
actually allocate a new array, then just pass the result of filter to 
std.array.array.

As for the lambda syntax, there has been some discussion of simplifying it, 
but there are potential issues with it, and so for the moment, it's staying 
as-is.

- Jonathan M Davis


Re: quickSort

2011-09-13 Thread %u
i have qustion why filter can't return int[]
and if lambda return  the last Expression without return keyword it would much
cleaner


Re: quickSort

2011-09-13 Thread Timon Gehr

On 09/14/2011 04:12 AM, Timon Gehr wrote:

On 09/14/2011 03:34 AM, hdsh wrote:

this my try

int[] quickSort(int[] arr) {
int[] result = quickSort(filter!(arr< arr[0])(arr)) ~ arr[0] ~
quickSort(filter!(arr> arr[0])(arr));
}

but it fail to compile


Note that this approach is an inefficient way of implementing a sorting
routine.

This works:

int[] quickSort(int[] arr) {
if(!arr.length) return [];
return quickSort(array(filter!((a){return a < arr[0];})(arr))) ~ arr[0] ~
quickSort(array(filter!((a){return a > arr[0];})(arr)));
}



Sry, accidentally sent a first draft. This is how it should have looked.

int[] quickSort(int[] arr) {
if(!arr.length) return [];
return quickSort(array(filter!((a){return a < arr[0];})(arr))) ~ 
arr[0] ~

    quickSort(array(filter!((a){return a >= arr[0];})(arr[1..$])));
}





I'll go quickly through how I fixed it:


int[] quickSort(int[] arr) {
if(!arr.length) return []; // base case for recursion
return // return statement for giving back a result
quickSort(array( // turn the lazy filter range into an array
filter!(
(a){return a < arr[0];} // delegate literal passed to filter
)(arr))) ~ arr[0] ~
quickSort(array(filter!(
(a){return a >= arr[0];} //allow multiple elements that are equal to the
pivot element
)(arr[1..$]))); // only include the pivot once
}


If you have particular questions about this solution, feel free to ask.



















Re: quickSort

2011-09-13 Thread Timon Gehr

On 09/14/2011 03:34 AM, hdsh wrote:

this my try

int[] quickSort(int[] arr) {
 int[] result = quickSort(filter!(arr<  arr[0])(arr)) ~ arr[0] ~
quickSort(filter!(arr>  arr[0])(arr));
}

but it fail to compile


Note that this approach is an inefficient way of implementing a sorting 
routine.


This works:

int[] quickSort(int[] arr) {
if(!arr.length) return [];
return quickSort(array(filter!((a){return a < arr[0];})(arr))) ~ 
arr[0] ~

quickSort(array(filter!((a){return a > arr[0];})(arr)));
}

I'll go quickly through how I fixed it:


int[] quickSort(int[] arr) {
if(!arr.length) return []; // base case for recursion
return // return statement for giving back a result
quickSort(array( // turn the lazy filter range into an array
filter!(
(a){return a < arr[0];} // delegate literal passed to filter
)(arr))) ~ arr[0] ~
quickSort(array(filter!(
(a){return a >= arr[0];} //allow multiple elements that are 
equal to the pivot element

)(arr[1..$]))); // only include the pivot once
}


If you have particular questions about this solution, feel free to ask.






Re: quickSort

2011-09-13 Thread Jonathan M Davis
On Wednesday, September 14, 2011 01:34:34 hdsh wrote:
> this my try
> 
> int[] quickSort(int[] arr) {
> int[] result = quickSort(filter!(arr < arr[0])(arr)) ~ arr[0] ~
> quickSort(filter!(arr > arr[0])(arr));
> }
> 
> but it fail to compile

filter does not return an array. It returns a new range which wraps the 
original array. As you iterate over the range, it skips elements which don't 
match the predicate. If you want to make an array out of it, you use 
std.array.array, but that allocates a new array. But as filter doesn't return 
int[], you can't pass its result to your quickSort function, nor can you 
concatenate it (if you want to concatenate ranges, you use std.range.chain, 
which chains them together without allocating anything - it just goes to each 
successive range when iterating over it). Normally, range-based functions are 
templated so that they can deal with a variety of range types.

If all you're looking for is a sort function, then you can use 
std.algorithm.sort, but if you're just trying to implement quick sort in D, 
because you want to implement it in D, then you're going to have to rework how 
your algorithm works. Either, you're going to have to templatize it (and use 
chain), use array (which would be less than efficient), or you're going to have 
to use something other than filter.

Personally, I'd advise reworking it so that it doesn't use filter if you want 
it to be efficient. Using std.array.array would work but would be inefficient, 
whereas templatizing quickSort might run into trouble. I'm not sure whether 
such a recursive templated function would work or not. It would depend on 
whether each call to filter required a new template instantiation or not.

In any case, your core problem here is the fact that filter does not return 
int[]. It returns a new range type.

- Jonathan M Davis


quickSort

2011-09-13 Thread hdsh
this my try

int[] quickSort(int[] arr) {
int[] result = quickSort(filter!(arr < arr[0])(arr)) ~ arr[0] ~
quickSort(filter!(arr > arr[0])(arr));
}

but it fail to compile