Challenge 1

Create a script to demonstrate Ackermann function. The Ackermann function is defined as below, m and n are positive number:

A(m, n) = n + 1 if m = 0 A(m, n) = A(m - 1, 1) if m > 0 and n = 0 A(m, n) = A(m - 1, A(m, n - 1)) if m > 0 and n > 0

As a challenge, that’s very clear. That is very close to the code you’d need.

#!/usr/bin/env perl

use strict;
use warnings;
use utf8;
use feature qw{ postderef say signatures state switch };
no warnings
    qw{ experimental::postderef experimental::smartmatch experimental::signatures };

say a( 1, 2 );
say a( 2, 2 );
say a( 2, 5 );
exit;

sub a ( $m, $n ) {
    die 'Invalid input' unless $m >= 0 && $n >= 0;
    return $n + 1 if $m == 0;
    return a( $m - 1, 1 ) if $m > 0 && $n == 0;
    return a( $m - 1, a( $m, $n - 1 ) ) if $m > 0 && $n > 0;
}

I mean, adding return and sigils and replacing and with && and you’re mostly there.

This is my code as uploaded, but looking back, using Memoize so repeated lookups are handled would be a quick thing to make this very recursive code faster.

ADDENDUM: I used Memoize and Benchmark to test, and using a memoized function made it, for a(2,5), 15x faster. I mean, it went from 45 millionths of a second to 3 millionth of a second, but speed is speed, and as we get to higher values and deeper recursion, it adds up.

ADDENDUM 2: “It adds up” does not say enough. This is creazy recursive,and all the times you hit return $n + 1 if $m == 0 means you can get $n to a(0,5440808), which is where my code died. I think that’s a big recursive stack problem, but I’m not sure. I’ve seen others mention bigint, and I’m not sure I won’t have to go there.

Challenge 2

Create a script to parse URL and print the components of URL. According to Wiki page, the URL syntax is as below:

scheme:[//[userinfo@]host[:port]]path[?query][#fragment]

For example: jdbc:mysql://user:password@localhost:3306/pwc?profile=true#h1

   scheme:   jdbc:mysql
   userinfo: user:password
   host:     localhost
   port:     3306
   path:     /pwc
   query:    profile=true
   fragment: h1

I had problems with this one, which I explain in the comments.

#!/usr/bin/env perl

use strict;
use warnings;
use utf8;
use feature qw{ postderef say signatures state switch };
no warnings
    qw{ experimental::postderef experimental::smartmatch experimental::signatures };

# Create a script to parse URL and print the components of URL.
# According to Wiki page, the URL syntax is as below:

# scheme:[//[userinfo@]host[:port]]path[?query][#fragment]

my @list;
push @list, 'ftp://ftp.cerias.purdue.edu/pub/dict/README.txt';
push @list, 'http://slashdot.org/';
push @list, 'https://en.wikipedia.org/wiki/URL';
push @list, 'https://github.com/manwar/perlweeklychallenge-club/pulse';
push @list, 'https://mail.google.com/mail/u/0/#inbox/FMfcg';
push @list, 'https://perlweeklychallenge.org/blog/perl-weekly-challenge-017/';
push @list, 'https://practimer.me:443/#5m0s';
push @list, 'https://www.perlmonks.org/?node_id=818843';
push @list, 'jdbc:mysql://user:password@localhost:3306/pwc?profile=true#h1';

@list = @ARGV if scalar @ARGV; # replace test list if anything is entered

# by the URL definition on wikipedia, jdbc:mysql is not a valid scheme
# and the scheme contains a trailing colon.

# Notes on implementation:
# + this is VERY ascii-centric code, and unicode and emoji are allowed
#   in URLs. Take, for example, i❤️tacos.ws
# + schemas and TLDs are constrained, not just to ascii, but to a small
#   (but larger than before) list. Yeah, you can override this with your
#   hosts file, but otherwise, all URLs should end (case-insensitive)
#   with a string in this list:
#       http://data.iana.org/TLD/tlds-alpha-by-domain.txt
# + similarly, the lists for path and query are limited to values
#   fitting my dataset. There have been path separator bugs: IE
#   would count \ as a separator, while Mozilla would not, so
#   you could hide information from Windows browsers /with\this\path

# So, this is a very naive implementation, needing more work before
# it can be trusted with real-world URLs. So, except when it's done
# for fun, like here, use something like Mojo::URL to split it up
# for you https://metacpan.org/pod/Mojo::URL

for my $url ( sort @list ) {
    my ( $scheme, $userinfo, $host, $port, $path, $query, $fragment ) =
        $url =~ m{
        ^
        (\w[A-Za-z0-9\+\.\-\:]+)://   # schema
        (?:([^@]+)@)?                 # userinfo
        ([\w\.]+)                     # host
        (?:\:(\d+))?                  # port
        (/[\w/\+\.\-]*)               # path
        (?:\?([\w/\+\.\-\=]+))?       # query
        (?:\#([^#]+))?                # fragment
        $
        }mxis;
    $scheme   //= '';
    $userinfo //= '';
    $host     //= '';
    $port     //= '';
    $path     //= '';
    $query    //= '';
    $fragment //= '';

    say <<"END";
    URL         $url
    scheme      $scheme
    userinfo    $userinfo
    host        $host
    port        $port
    path        $path
    query       $query
    fragment    $fragment
END
}

__DATA__

    URL         ftp://ftp.cerias.purdue.edu/pub/dict/README.txt
    scheme      ftp
    userinfo
    host        ftp.cerias.purdue.edu
    port
    path        /pub/dict/README.txt
    query
    fragment

    URL         http://slashdot.org/
    scheme      http
    userinfo
    host        slashdot.org
    port
    path        /
    query
    fragment

    URL         https://en.wikipedia.org/wiki/URL
    scheme      https
    userinfo
    host        en.wikipedia.org
    port
    path        /wiki/URL
    query
    fragment

    URL         https://github.com/manwar/perlweeklychallenge-club/pulse
    scheme      https
    userinfo
    host        github.com
    port
    path        /manwar/perlweeklychallenge-club/pulse
    query
    fragment

    URL         https://mail.google.com/mail/u/0/#inbox/FMfcg
    scheme      https
    userinfo
    host        mail.google.com
    port
    path        /mail/u/0/
    query
    fragment    inbox/FMfcg

    URL         https://perlweeklychallenge.org/blog/perl-weekly-challenge-017/
    scheme      https
    userinfo
    host        perlweeklychallenge.org
    port
    path        /blog/perl-weekly-challenge-017/
    query
    fragment

    URL         https://practimer.me:443/#5m0s
    scheme      https
    userinfo
    host        practimer.me
    port        443
    path        /
    query
    fragment    5m0s

    URL         https://www.perlmonks.org/?node_id=818843
    scheme      https
    userinfo
    host        www.perlmonks.org
    port
    path        /
    query       node_id=818843
    fragment

    URL         jdbc:mysql://user:password@localhost:3306/pwc?profile=true#h1
    scheme      jdbc:mysql
    userinfo    user:password
    host        localhost
    port        3306
    path        /pwc
    query       profile=true
    fragment    h1

As I said, I do not trust this to be complete. I do trust it to handle all entries in my test suite, but that’s not enough.

I do, however, trust Mojo::URL.

#!/usr/bin/env perl

use strict;
use warnings;
use utf8;
use feature qw{ postderef say signatures state switch };
no warnings
    qw{ experimental::postderef experimental::smartmatch experimental::signatures };

use Mojo::URL;

# Create a script to parse URL and print the components of URL.
# According to Wiki page, the URL syntax is as below:

# scheme:[//[userinfo@]host[:port]]path[?query][#fragment]

my @list;
push @list, 'ftp://ftp.cerias.purdue.edu/pub/dict/README.txt';
push @list, 'http://slashdot.org/';
push @list, 'https://en.wikipedia.org/wiki/URL';
push @list, 'https://github.com/manwar/perlweeklychallenge-club/pulse';
push @list, 'https://mail.google.com/mail/u/0/#inbox/FMfcg';
push @list, 'https://perlweeklychallenge.org/blog/perl-weekly-challenge-017/';
push @list, 'https://practimer.me:443/#5m0s';
push @list, 'https://www.perlmonks.org/?node_id=818843';
push @list, 'mysql://user:password@localhost:3306/pwc?profile=true#h1';

# Mojo::URL does NOT like the example URL
push @list, 'jdbc:mysql://user:password@localhost:3306/pwc?profile=true#h1';

@list = @ARGV if scalar @ARGV;    # replace test list if anything is entered

for my $url ( sort @list ) {
    my $mojo     = Mojo::URL->new($url);
    my $scheme   = $mojo->scheme || '';
    my $userinfo = $mojo->userinfo || '';
    my $host     = $mojo->host || '';
    my $port     = $mojo->port || '';
    my $path     = $mojo->path || '';
    my $query    = $mojo->query || '';
    my $fragment = $mojo->fragment || '';

    say <<"END";
    URL         $url
    scheme      $scheme
    userinfo    $userinfo
    host        $host
    port        $port
    path        $path
    query       $query
    fragment    $fragment
END
}

If you have any questions or comments, I would be glad to hear it. Ask me on Twitter or make an issue on my blog repo.