Perl: the super-convenient pseudo-functional language

Submitted by metaperl on Fri, 05/12/2006 - 10:55am.

I work at a place where we show adult models online. I was building our monthly newsletter and realized that of the 30 models who I could choose for the newsletter, not all of them had all 4 required pictures.

So I needed to hit our content server and see if a model had all 4 pictures. My knowledge of functional programming came in handy, but look how easy this was to code in Perl:

#!/usr/bin/perl

use LWP::Simple;

my @stream = qw(
uexitexy
pitoiaLden
lopdfits
ricknoverY
and_so_on_for_35_models
);

# type ModelName = String
# type ImageNumber = Int
# type URLString = String
# img :: ModelName -> ImageNumber -> URLString
sub img {
my $s = shift;
my $i = shift;

my $prefix = substr $s, 0, 1 ;
$prefix = uc $prefix;

"http://free.content.ourwebsite.com/fcs/$prefix/$s/${i}_th_.jpg";
}

# does a model have all 4 images?
# good_imgs :: [ URLString ] -> Bool
sub good_imgs {
my $s = shift;
for my $i (1..4) {
my $img = img($s, $i), $/;
return undef unless get($img) ;
}
return 1;
}

# grep is like Haskell's filter
my @ok = grep { good_imgs($_) } @stream ;

# print the models with all 4 images
print join "\n", @ok ;

This is my first time seeing how great _Haskell_ really is. Those type signatures make my Perl self-documenting. But the thing is, there is nothing close to libwww-perl for Haskell. It not only makes HTTP requests but comes with a pragmatic parser for everyday HTML.

Another thing is look how I could list the model names without bothering with quotes around the strings. The qw() operator in Perl allows one to input a list of strings without quotes by simply separating them with whitespace.

Submitted by evan on Sun, 06/04/2006 - 5:50pm.
I suspect thinking in terms of Perl will hold you back. Instead of special operators like %qw Haskell tends to use boring-ol functions like "words":
import List
import Char
import Monad

type URL = String

models = words "uexitexy pitoiaLden lopdfits etc"

modelUrl :: String -> Int -> URL
modelUrl name num = joinPath [baseurl, prefix, name, show num] ++ "_th_.jpg"
  where baseurl = "http://free.content.ourwebsite.com/fcs"
        prefix = [toUpper (head name)]
        joinPath = foldr1 (\a b -> a ++ '/' : b)

-- return True if URL exists.
testHTTP :: URL -> IO Bool
testHTTP url = ...   -- needs a library

-- like "all" but within a monad.
allM :: (a -> IO Bool) -> [a] -> IO Bool
allM pred []     = return True
allM pred (a:as) = do ok <- pred a
                      if ok then allM pred as else return False

main = do okModels <- filterM modelOk models
          putStrLn (unlines okModels)
       where modelOk model = allM testHTTP (map (modelUrl model) [1..4])
Submitted by evan on Sun, 06/04/2006 - 5:51pm.

(I think Perl is a better language for these sorts of one-off scripts.)

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.