Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

RFC: Monads in Perl (Send + More = Money)

by LanX (Saint)
on Dec 02, 2020 at 18:10 UTC ( [id://11124522]=perlmeditation: print w/replies, xml ) Need Help??

One of the attendants at German.pm online meeting yesterday pointed to these blogposts of MJ Dominus somehow complaining that Perl is too "clumsy" to reimplement a Haskell solution based on monads

see

Basically you have a nice linearized syntax implementing nested loops to find the solution for a number riddle

Let's say for concreteness that we would like to solve this cryptarithm puzzle:
S E N D + M O R E ----------- M O N E Y
This means that we want to map the letters S, E, N, D, M, O, R, Y to distinct digits 0 through 9 to produce a five-digit and two four-digit numerals which, when added in the indicated way, produce the indicated sum.

the proposed Perl code was actually the semantic translation of some Python code and was indeed clumsy (NB all those curlies at the end)

Now here my solution reusing some work I've done in the past with List Comprehensions

use strict; use warnings; use Data::Dump qw/pp dd/; =pod https://blog.plover.com/prog/haskell/monad-search.html https://blog.plover.com/prog/monad-search-2.html =cut # --- List comprehension sub from (&$;$) { my ($c_block, undef, $c_tail) = @_; my $var = \$_[1]; sub { for ( &$c_block ) { $$var = $_; $c_tail->() } } } sub when (&$){ # guard my ($c_block, $c_tail) = @_; sub { $c_tail->() if &$c_block } } # --- rem() Helper function to return digits 0..9 except @_ my %digits; @digits{0..9}=(); sub rem { # set difference my %h = %digits; delete @h{@_}; keys %h; } my ($send,$s,$e,$n,$d); my ($more,$m,$o,$r); my ($money,$y); my $do = # send from { rem 0 } $s => from { rem $s } $e => from { rem $s, $e } $n => from { rem $s,$e,$n } $d => # more from { rem 0,$s,$e,$n,$d } $m => from { rem $s,$e,$n,$d,$m } $o => from { rem $s,$e,$n,$d,$m,$o } $r => # money from { rem $s,$e,$n,$d,$m,$o,$r } $y => # guard when { "$s$e$n$d" + "$m$o$r$e" == "$m$o$n$e$y" } # output sub { pp [ "$s$e$n$d" , "$m$o$r$e" , "$m$o$n$e$y" ] } ; &$do;

Compilation started at Wed Dec 2 19:11:14 C:/Perl_524/bin\perl.exe -w d:/tmp/pm/send_more_money_monad.pl [9567, 1085, 10652] Compilation finished at Wed Dec 2 19:11:18

NB: It could be done better and faster, I've just coded this POC from scratch within an hour.

Please note that making it "lazy" is not really a problem, left for the interested reader.

So Monads in Perl are not that complicated ... or what am I missing? ;-)

Cheers Rolf
(addicted to the Perl Programming Language :)
Wikisyntax for the Monastery

Replies are listed 'Best First'.
Re: RFC: Monads in Perl (Send + More = Money)
by LanX (Saint) on Dec 13, 2020 at 17:28 UTC
    I tried to put use 5.10.0 into this script and found a problem ...

    > sub when (&$){                          # guard

    when can't be easily used, since it's reserved for given/when

    I tried to find another short (max 5 letters) synonym for if , but that's pretty difficult.

    my best guesses are

    • cond(ition)
    • prov(ided)
    • case
    • guard

    Synonym for while is easier, I'd choose whilst , this pair corresponds well with 'for/from'.

    any better idea for if ?

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://11124522]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others chanting in the Monastery: (4)
As of 2024-04-25 15:59 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found