И опыт, сын ошибок трудных
И гений, парадоксов друг

(А.С.Пушкин)

error-программирование

если мы знаем что бывает что-то не так, и мы хотим выполнить некие действия если что не так

чтобы справиться с нетотальностью функций у перловщиков есть несколько способов:

и у хаслелистов: Error

давайте озадачимся. пусть БД содержит следующие таблицы:

    users,     c полями :      number  uid    |   literal name
    phones,    с полями :      literal name   |   literal number
    codes,     с полями :      literal code   |   literal country

пусть нам необходимо выбрать из БД страну обитания персонажа (country), используя в качестве входных данных личный номер (uid). для простоты предположим, что телефонный код страны - это первые три знака телефонного номера (number)


перловщики

сначала - база данных в отдельном модуле DBP.pm:
#    file DBP.pm
package DBP;

use Exporter; 
@EXPORT = (init, findUser, getPhone, getCode, findByCode);

use vars qw(@EXPORT);

%users ; %phones ; %codes ;

sub init {
  %users  = (1 => 'Trinity',
             2 => 'Neo',
             3 => 'Morpheus',
             4 => 'Smith');

  %phones = ('Trinity'  => '123456',
             'Neo'      => '456789',
             'Morpheus' => '3759'); 

  %codes  = ('123' => 'USA',
             '456' => 'RUS');

  print "database initialized\n";

  return 0;
}

sub findUser { shift; $users{(shift)} ; }

sub getPhone { shift; $phones{(shift)} ; }

sub getCode {
  shift; my $number = shift;
  $number =~ s/^(...).*$/\1/;
  return $number;
}

sub findByCode { shift; $codes{(shift)} ; }

1;
главную функцию программы поместим в файл main.pl

eval BLOCK

#!/usr/bin/perl
#    file main.pl

use DBP;

$userid;

DBP->init;

read (STDIN, $userid, 1);

while (<>) {
  countryName ($userid);
  read (STDIN, $userid, 1);
}

exit 0;

sub countryName {
  my $d = shift;
  my $ans = eval {
    my $u = DBP->findUser   ($d) or die "cant find user\n";
    my $p = DBP->getPhone   ($u) or die "cant find phone\n";
    my $c = DBP->getCode    ($p) or die "cant find code\n";
    my $f = DBP->findByCode ($c) or die "cant find country\n";
  };
  if ($@) { print $@; }
  else    { print $ans . "\n"; }
}

__DIE__

#!/usr/bin/perl
#    file main.pl

use DBP;

local $SIG{__DIE__} = \&handlerDie;

$userid;

DBP->init;

read (STDIN, $userid, 1);

while (<>) {
  countryName ($userid);
  read (STDIN, $userid, 1);
}

exit 0;

sub countryName {
  my $u, $p, $c, $f;
  my $d = shift;
  my $ans = eval {
    $u = DBP->findUser   ($d) or die "cant find user\n";
    $p = DBP->getPhone   ($u) or die "cant find phone\n";
    $c = DBP->getCode    ($p) or die "cant find code\n";
    $f = DBP->findByCode ($c) or die "cant find country\n";
  };
  unless ($@) { print $ans . "\n"; }
}

sub handlerDie {
  print "error detected : $_[0]";
}

Try::Tiny

#!/usr/bin/perl
#    file main.pl

use DBP; use Try::Tiny;

$userid;

DBP->init;

read (STDIN, $userid, 1);

while (<>) {
  countryName ($userid);
  read (STDIN, $userid, 1);
}

exit 0;

sub countryName {
  my $u, $p, $c, $f;
  my $d = shift;

  try   { $u = DBP->findUser ($d) or die "cant find user\n"; }
  catch { warn "caught error: $_"; };

  try   { $p = DBP->getPhone ($u) or die "cant find phone\n"; }
  catch { warn "caught error: $_"; };

  try   { $c = DBP->getCode ($p) or die "cant find code\n"; }
  catch { warn "caught error: $_"; };

  try   { $f = DBP->findByCode ($c) or die "cant find country\n"; }
  catch { warn "caught error: $_"; }

  finally { print $f . "\n"; }
}


хаскелисты

сначала - БД в файле DBC.hs:

module DBC (findUser, getPhone, getCode, findByCode) where

data User  = U { uname  :: String, uid     :: Integer } deriving (Show)
data Phone = P { number :: String, pname   :: String  } deriving (Show)
data Code  = C { digs   :: String, country :: String  } deriving (Show)

dbusers = 
  [ U {uname = "Neo",      uid = 4}
  , U {uname = "Tom",      uid = 3}
  , U {uname = "Morpheus", uid = 2}
  , U {uname = "Cipher",   uid = 1}
  , U {uname = "Smith",    uid = 0}
  ]

dbphones = 
  [
  , P {number = "123456", pname = "Morpheus"}
  , P {number = "456012", pname = "Tom"}
  , P {number = "65789",  pname = "Smith"}
  , P {number = "12",     pname = "Cipher"}
  ]

dbcodes = 
  [ C {digs = "123", country = "USA"}
  , C {digs = "456", country = "RUS"}
  ]


-- | interface:

findUser :: Integer -> Either String String
findUser n = case filter (\x -> uid x == n) dbusers of
  []  -> Left "user not found";
  [x] -> Right $ uname x 

getPhone :: String -> Either String String 
getPhone s = case filter (\x -> pname x == s) dbphones of 
  []  -> Left "phone not found";
  [x] -> Right $ number x

getCode :: String -> Either String String 
getCode s = if (length s) < 3 
  then Left "code not found"
  else Right (take 3 s) 

findByCode :: String -> Either String String
findByCode s = case filter (\x -> digs x == s) dbcodes of
  []  -> Left "country not found"
  [x] -> Right $ country x

код главной функции в файле main.hs:

module Main where

import DBC
import Control.Monad.Error

main :: IO (Either String String)
main = readLn >>= \n -> return $ catchError (countryName n) handle

countryName :: Integer -> Either String String
countryName = \n -> findUser n >>= getPhone >>= getCode >>= findByCode

handle :: String -> Either String String 
handle = \e -> case e of
  "user not found"    -> Left  "no such user" 
  "phone not found"   -> Right "this user has not have phone" 
  "code not found"    -> Left  "no code for this number" 
  "country not found" -> Right "NullCountry" 
  _                   -> Left  "unknown error"

это - все