=begin pod :kind("Language") :subkind("Language") :category("migration")

=TITLE Haskell to Raku - nutshell

=SUBTITLE Learning Raku from Haskell, in a nutshell: what do I already know?

Haskell and Raku are I<very> different languages. This is obvious.
However, that does not mean there are not similarities or shared ideas!
This page attempts to get a Haskell user up and running with Raku. The
Haskell user may find that they need not abandon all of their Haskelly
thoughts while scripting in Raku.

Note that this should not be mistaken for a beginner tutorial or overview of
Raku; it is intended as a technical reference for Raku learners with a
strong Haskell background.


=head1 Types

=head2 Types vs values

In Haskell, you have type level programming and then value level programming.

    =begin code :lang<haskell>
    plusTwo :: Integer -> Integer   -- Types
    plusTwo x = x + 2               -- Values
    =end code

You do not mix types and values in Haskell like the below

    =begin code :lang<haskell>
    plusTwo 2          -- This is valid
    plusTwo Integer    -- This is not valid
    =end code

In Raku, types (AKA type objects) live on the same level as values

    =begin code
    sub plus-two(Int $x --> Int) { $x + 2 }

    plus-two(2);    # This is valid
    plus-two(Int);  # This is valid
    =end code

I will illustrate this unique aspect of Raku with one more example:

    =begin code
    multi sub is-string(Str $ --> True) {}
    multi sub is-string(Any $ --> False) {}

    is-string('hello');    #True
    is-string(4);          #False
    =end code

=head2 Maybe

In Haskell, you have a Maybe type that allows you to forgo the worry of null types.
Let's say you have a hypothetical function that parses a String to an Integer:

    =begin code :lang<haskell>
    parseInt :: String -> Maybe Integer

    case parseInt myString of
      Just x  -> x
      Nothing -> 0
    =end code

In Raku, since type objects coexist with regular objects, we have the concept
of Defined and Undefined objects. Plain type objects are undefined while
instantiated objects are defined.

    =begin code
    sub parse-int(Str $s --> Int) { ... }

    my $string = {...};
    given parse-int($string) {
      when Int:D { $_ }
      when Int:U { 0 }
    }
    =end code

So in Raku we have type constraints that indicate the definedness of a type. These are

    =begin code
    Int:D; # This is a defined Int.
    Int:U; # This is an undefined Int, AKA a type object
    Int:_; # This is either defined or undefined.
    =end code

If we wanted to be explicit in the above example (probably a good idea), we could add
the C<:_> constraint on the return type. This would let the user know that they should account
for both defined and undefined return values. We could also use other methods and constructs
that specifically test for definedness.

    =begin code
    sub parse-int(Str $s --> Int:_) { ... }

    # One way to do it
    my $string = {...};
    given parse-int($string) {
      when Int:D { $_ }
      when Int:U { 0 }
    }

    # Another way to do it
    my Int $number = parse-int($string);
    if $number.defined { $number } else { 0 }


    # A better way
    with parse-int($string) { $_ } else { 0 }

    # With the defined-or operator
    parse-int($string) // 0
    =end code

The C<with> operator that you see above is like C<if>, except it explicitly tests for definedness and then
passes the result to the following block. Similarly, C<without> tests that the object is undefined and also
passes the result to the following block.

For more natural control flow with undefined and defined types, Raku introduces C<andthen> and C<orelse>.

    =begin code
    sub parse-int(Str $s --> Int:_) { ... }

    my $string = {...};
    my $result = parse-int($string) orelse 0;

    sub hello() { say 'hi' }
    hello() andthen say 'bye';
    =end code

=begin comment
TODO: include a better example for andthen that makes sense. Maybe using promise objects?
=end comment

So in practice, Raku does not have the concept of a null type, but rather of
defined or undefined types.

=head2 Data definitions

Raku is fundamentally an object oriented language. However, it also gives you
the freedom to write in virtually any paradigm you wish. If you only want to
pure functions that take an object and return a new object, you can certainly do
so.

Here is a Haskell code example:

    =begin code :lang<haskell>
    data Point = Point x y

    moveUp :: Point -> Point
    moveUp (Point x y) = Point x (y + 1)
    =end code

And an equivalent Raku example:

    =begin code
    class Point { has $.x; has $.y; }

    sub move-up(Point $p --> Point) {
      Point.new(x => $p.x, y => $p.y + 1)
    }
    =end code

The code I illustrated above is an example of a
L<Product Type|https://wiki.haskell.org/Algebraic_data_type>. If instead you'd like to
write a Sum Type, there is not an exact equivalent in Raku. The closest thing
would be an L<Enum|/language/typesystem#enum>.

    =begin code :lang<haskell>
    data Animal = Dog | Cat | Bird | Horse

    testAnimal :: Animal -> String
    testAnimal Dog   = "Woof"
    testAnimal Horse = "Neigh"
    =end code

Although it does not fit the same exact use cases, it can be used in putting
constraints on types.

    =begin code
    enum Animal < Dog Cat Bird Horse >;

    proto sub test-animal( Animal        ) {*}
    multi sub test-animal( Dog           ) { 'Woof' }
    multi sub test-animal( Animal::Horse ) { 'Neigh'  }   # more explicit

    say test-animal Animal::Dog;                          # more explicit
    say test-animal Horse;
    =end code

=head2 Type aliases and subsets

In Haskell, you can alias an existing type to simply increase clarity of intent
and re-use existing types.

    =begin code :lang<haskell>
    type Name = String

    fullName :: Name -> Name -> Name
    fullName first last = first ++ last
    =end code

The equivalent in Raku is the following.

    =begin code
    my constant Name = Str;

    sub full-name ( Name \first, Name \last --> Name ) { first ~ last }
    =end code

It should be noted that in Raku, one can also create a subset of an existing type.

    =begin code
    subset Name of Str where *.chars < 20;

    sub full-name(Name $first, Name $last) {
      $first ~ $last
    }

    full-name("12345678901234567890111", "Smith") # This does not compile, as the first parameter
                                                  # doesn't fit the Name type
    =end code

=head2 Typeclasses

TODO

=begin comment
explain how Raku roles compare to Haskell typeclasses
=end comment

=head1 Functions

=head2 Definitions and signatures

=Pattern Matching

Haskell makes heavy use of pattern matching in function definitions.

    =begin code :lang<haskell>
    greeting :: String -> String
    greeting  ""   = "Hello, World!"
    greeting "bub" = "Hey bub."
    greeting  name = "Hello, " ++ name ++ "!"
    =end code

Raku does this as well! You just use the C<multi> keyword to signify that it is a multiple dispatch
function.

    =begin code
    proto greeting ( Str   --> Str ) {*}
    multi greeting ( ""    --> "Hello, World!" ) {}
    multi greeting ( "bub" --> "Hey bub." ) {}
    multi greeting ( \name ) { "Hello, " ~ name ~ "!" }
    =end code

The C<proto> declarator is not necessary, but can sometimes aid in making sure that all multis
follow your business rules. Using a variable name in the signature of the proto would provide
more information in error messages, and for introspection.

    =begin code
    proto greeting ( Str \name --> Str ) {*}

    say &greeting.signature;                  # (Str \name --> Str)
    =end code

An interesting thing to note in the Raku code above is that passing values like C<'bub'> as a
function parameter is just syntax sugar for a C<where> guard.

=Guards

Using the example from the "Pattern Matching" section of this page, you can see the guards that are
used behind the scenes to constrain our function arguments.

    =begin code
    multi greeting ( ""    --> "Hello, World!" ) {}
    multi greeting ( "bub" --> "Hey bub." ) {}

    # The above is the same as the below

    multi greeting(Str \name where ''    ) {'Hello, World!'}
    multi greeting(Str \name where 'bub' ) {'Hey bub.'}

    # The above is the same as the below, again.

    multi greeting(Str \name where $_ ~~ ''   ) {'Hello, World!'}
    multi greeting(Str \name where $_ ~~ 'bub') {'Hey bub.'}
    =end code

C<$_> is known as the topic variable. It assumes the form of whatever is
appropriate. The smartmatch operator C<~~> figures out the best way to determine
if the left matches the right, be it number ranges, strings, etc. Our three
examples above go from most sugared (top), to least sugared (bottom).

The bottom examples above could be wrapped in curly braces, making it more
obvious that it is a code block. Note that a where clause may also take an
explicit Callable.

    =begin code :preamble<sub some-subroutine {};>
    multi greeting(Str \name where { $_ ~~ '' } ) {'Hello, World!'}

    multi greeting(Str \name where -> $thing { $thing ~~ '' } ) {'Hello, World!'}

    multi greeting ( Str \name where { Bool.pick } --> 'True' ){}

    multi greeting ( Str \name where &some-subroutine ){…}
    =end code

If you read the section in this page on subsets, you'll notice that "where" is used in the making of
subsets as well as here. The usage of "where" in both areas is exactly the same.

When using C<where>, note that the order of definition is important, just like in Haskell.

    =begin code
    multi greeting ( Str \name where '' --> 'Hello, World!' ){}
    multi greeting ( Str \name where { Bool.pick } --> 'True' ){}
    multi greeting ( Str \name where 'bub' --> 'Hey, bub.' ){}

    say greeting ''   ; # will never say True
    say greeting 'bub'; # about 50% of the time it will say True
    =end code

=Argument Deconstruction

TODO

=head2 Currying

TODO

.assuming vs currying

method chaining vs currying

=head2 Composing

TODO

show function composition operator. Maybe explain a more native Raku way to do this though.

=head1 Case / matching

Haskell makes heavy use of case matching like the below:

    =begin code :lang<haskell>
    case number of
      2 -> "two"
      4 -> "four"
      8 -> "eight"
      _ -> "don't care"
    =end code

In Raku you can achieve this same thing with the given/when structure:

    =begin code
    my $number = {...};
    given $number {
      when 2  { "two" }
      when 4  { "four" }
      when 8  { "eight" }
      default { "don't care" }
    }
    =end code

Note that the order of the C<when>'s is also significant, just like with the C<where>'s in the
guard section of this page.

=head1 Lists

TODO

explain differences between Raku Arrays, Sequences, and Lists. Explain data shapes in regards
to the C<@> sigil. Explain how you can convert an Array to a flattened list of objects with C<|@>

data shapes become quite intuitive, but it takes a bit of practice.

=head2 List comprehensions

There are no explicit list comprehensions in Raku. But you can achieve list comprehensions
a couple of different ways.

Here is a trivial example in Haskell:

    =begin code :lang<haskell>
    evens = [ x | x <- [0..100], even x ]
    =end code

And now in Raku:

    =begin code
    # using `if` and `for`
    my @evens = ($_ if $_ %% 2 for 0..100);

    # using gather/take to build a Seq
    my $evens = gather for 0..100 { take $_ if $_ %% 2 };

    # using gather/take to build an Array
    my @evens = gather for 0..100 { take $_ if $_ %% 2 };
    =end code

Since C<for> is always eager it is generally better to use C<map> or C<grep> which
will inherit the laziness or eagerness of its list argument.

    =begin code
    my @evens = map { $_ if $_ %% 2 }, 0..100;

    my @evens = grep { $_ %% 2 }, 0..100;

    # using a Whatever lambda
    my @evens = grep  * %% 2,  0..100;
    =end code

Here is the creation of tuples in Haskell:

    =begin code :lang<haskell>
    tuples = [(i,j) | i <- [1,2],
                      j <- [1..4] ]
    -- [(1,1),(1,2),(1,3),(1,4),(2,1),(2,2),(2,3),(2,4)]
    =end code

And in Raku:

    =begin code
    my @tuples = 1,2  X  1..4;
    # [(1,1), (1,2), (1,3), (1,4), (2,1), (2,2), (2,3), (2,4)]
    =end code

See this design document for more information on what kinds of list comprehensions are possible
in: L<https://design.raku.org/S04.html#The_do-once_loop>.

As you can see, when you get into some more advanced Haskell list comprehensions, Raku
does not translate exactly the same, but it's possible to do the same things, nonetheless.

=head2 Fold

Fold in Haskell is called Reduce in Raku.

    =begin code :lang<haskell>
    mySum = foldl (+) 0 numList
    =end code

    =begin code
    my @numbers = {...};
    reduce { $^a + $^b }, 0, |@numbers;
    @numbers.reduce: {$^a + $^b}
    =end code

However, in Raku, if you want to use an infix operator (+ - / % etc)
there is a nice little helper called the Reduction metaoperator.

    =begin code
    my @numbers = {...};
    [+] @numbers     # This is the same
    [+] 0, |@numbers # as this
    =end code

It inserts the operator in between all values in the list and produces a result, just like Fold.

In Haskell you, you have foldl and foldr. In Raku, this difference is determined by the
associativity attached to the operator/subroutine.

    =begin code
    sub two-elem-list ( \a, \b ) { ( a, b ) }

    # you can use a subroutine as an infix operator
    say 'a' [&two-elem-list] 'b'; # (a b)

    # as the reduction prefix metaoperator takes an infix operator, it will work there too;
    [[&two-elem-list]] 1..5;           # ((((1 2) 3) 4) 5)
    say (1..5).reduce: &two-elem-list; # ((((1 2) 3) 4) 5)

    # right associative
    sub right-two-elem-list( \a, \b ) is assoc<right> { ( a, b ) }
    say (1..5).reduce: &right-two-elem-list; # (1 (2 (3 (4 5))))

    # XXX there is possibly a bug here as this currently doesn't look at
    # XXX the associativity of &right-two-elem-list and just always does left assoc
    say [[&right-two-elem-list]] 1..5;

    # chaining
    say [<] 1..5;            # True
    say (1..5).reduce: &[<]; # True
    =end code

=head2 Map

TODO

=head2 Ranges

Haskell and Raku both allow you to specify ranges of values.

    =begin code :lang<haskell>
    myRange1 = 10..100
    myRange2 = 1..        -- Infinite
    myRange3 = 'a'..'h'   -- Letters work too
    =end code

    =begin code
    my $range1 = 10..100;
    my $range2 = 1..*;      # Infinite
    my $range3 = 'a'..'h';  # Letters work too
    =end code

=head2 Laziness vs eagerness

In the examples above, you have the concept of laziness displayed very plainly. Raku has laziness
only where it makes the most sense. For example, in the range 10..100, this is eager because it has
a definite end. If a list does not have a definite end, then the list should clearly be lazy.

    =begin code
    (1 .. 100).is-lazy; # False
    (1 .. Inf).is-lazy; # True
    =end code

These are the "sane defaults" that Raku takes pride in. But they are still defaults and can be
changed into one or the other.

    =begin code
    (1 .. 100).lazy.is-lazy;       # True
    (1 .. 100).lazy.eager.is-lazy; # False
    =end code

=head1 Contexts (let-in / where)

TODO

explain how C<given/when> and C<with/without> and C<for loops> open lexical scopes with the argument as the context.

compare it to let/in and where constructs maybe?

=head1 Parsers

=head2 Parser combinators vs grammars

TODO

=head1 Tail Call Optimization or Tail Call Elimination

Haskell and many other functional programming languages use tail call optimization, also
sometimes called tail call elimination, to remove the stack overhead of some types
of recursive function calls.

There is nothing in the Raku language specification forbidding the implementation of this
class of optimization, but no current implementation has it.

Please note that many Haskell looping constructs use recursive function calls.  Haskell programs
would encounter stack overflow errors more often without tail call optimization. The standard
Raku looping constructs are not built on recursive function calls, which makes the feature
less important.

=begin comment

### Guidelines for contributions:

Headers should contain the text that a Haskell user might search for, since
those headings will be in the Table of Contents generated for the top of
the document.

We use POD =item instead of =head3 or =head4 for identical bits that need not
appear in the table of contents.

This article does not describe in detail language features that Haskell doesn't
have at all, instead referring to other documents.

Example code and links to other documents should be favored over long
explanations of details better found elsewhere.

Finally, if a real user asks a Haskell to Raku question that is not being
answered here, please add it to the document. Even if we do not have a good
answer yet, that will be better than losing the information about a real need.

=end comment

=end pod


# vim: expandtab softtabstop=4 shiftwidth=4 ft=perl6
