- Какова вероятность встретить на Невском динозавра?
- 50%
- ?!
- Ну, или встречу, или не встречу.

(из анекдотов о блондинке)

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

если нам пофиг, что результата нет, а есть Ашипка, и исправлять Ашипку нам влом, но однако мы все-же хотим знать, что именно пошло не так

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

и у хаскельнутых Either

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

users, c полями : (int) uid (string) name
phones, с полями : (string) name (string) number
codes, с полями : (int) code (string) country

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

для простоты предположим, что телефонный код страны - это первые три знака телефонного номера


сионисты

главную функцию программы поместим в файл main.c
// file main.c

extern void init (void) ;
extern char* countryName (int) ;

int 
main (void) 
{
  init () ;

  for ( ; ;) 
  {
    int uid ;
    printf ("userID : ") ;
    scanf ("%i", &uid) ;
    printf ("%s \n", countryName (uid)) ; 
  } ;

  return 0 ;
}
заголовочный файл базы simpleDB.h:
// file simpleDB.h

#include <stdio.h>
#include <string.h>

struct user  { char* name ;   int   uid ;     } ;
struct phone { char* number ; char* name ;    } ;
struct code  { char* code ;   char* country ; } ;

struct user  users [5] ;
struct phone phones[4] ;
struct code  codes [2] ;

char mcod [4] ;

char* nullUser    = "user not found" ;
char* nullPhone   = "phone not found" ;
char* nullCode    = "code not found" ;
char* nullCountry = "country not found" ;
код базы - файл simpleDB.c:
// file simpleDB.c

#include "simpleDB.h" 

void 
init (void) 
{
  struct user a, b, c, d, s ;
  struct code e, f ;
  struct phone g, h, i, j ;

  a.name = "Neo" ;        a.uid = 1 ;             users[0] = a ;
  b.name = "Cipher" ;     b.uid = 2 ;             users[1] = b ;
  c.name = "Morpheus" ;   c.uid = 3 ;             users[2] = c ;
  d.name = "Trinity" ;    d.uid = 4 ;             users[3] = d ;
  s.name = "Switch" ;     s.uid = 5 ;             users[4] = s ;

  g.number = "123444" ;   g.name = "Neo" ;        phones[0] = g ;
  h.number = "456555" ;   h.name = "Cipher" ;     phones[1] = h ;
  h.number = "567888" ;   h.name = "Morpheus" ;   phones[2] = h ;
  j.number = "" ;         j.name = "Trinity" ;    phones[3] = j ;

  e.country = "USA" ;     e.code = "123" ;        codes[0] = e ;
  f.country = "RUS" ;     f.code = "456" ;        codes[1] = f ;

  printf ("db initiated\n") ;
}

char* 
findUser (int d) 
{
  int i = 0 ;
  for (i ; i < 5 ; i++)
    if (users[i].uid == d) return users[i].name ;
  return nullUser ;
} ;

char* 
getPhone (char* u) 
{
  int i = 0 ;
  for (i ; i < 4 ; i++)
    if (phones[i].name == u) return phones[i].number ;
  return nullPhone ;
} ;

char* 
getCode (char* p) 
{
  //  ---- dirty hack: 
  *mcod = '\0' ;
  strncpy(mcod, p, 3) ;

  //  ---- canonical: 
  // memcpy(mcod, p, 3) ;
  // mcod[3] = '\0' ; 

  if (strlen (mcod) == 3) return mcod ;
  else return nullCode ;
} ;

char* 
findByCode (char* mycod) 
{
  int i = 0 ;
  for (i ; i < 2 ; i++)
    if (!strcmp (mycod, codes[i].code)) return codes[i].country ; 
  return nullCode ;
}

будем кодить функцию char* countryName (int), помещая сей продукт в файл work.c


null

// file work.c

extern char* nullUser ;
extern char* nullPhone ;
extern char* nullCode ;
extern char* nullCountry ;

char* 
countryName (int d) 
{
  char *ans ;

  ans = findUser     (d) ; if (!strcmp (ans, nullUser))    return 0 ;
  ans = getPhone   (ans) ; if (!strcmp (ans, nullPhone))   return 0 ;
  ans = getCode    (ans) ; if (!strcmp (ans, nullCode))    return 0 ; 
  ans = findByCode (ans) ; if (!strcmp (ans, nullCountry)) return 0 ; 

  return ans ;
}

goto

// file work.c

extern char* nullUser ;
extern char* nullPhone ;
extern char* nullCode ;
extern char* nullCountry ;

char* 
countryName (int d) 
{
  char *ans ;

  ans = findUser     (d) ; if (!strcmp (ans, nullUser))     goto m1 ;
  ans = getPhone   (ans) ; if (!strcmp (ans, nullPhone))    goto m1 ;
  ans = getCode    (ans) ; if (!strcmp (ans, nullCode))     goto m1 ;
  ans = findByCode (ans) ; if (!strcmp (ans, nullCountry))  goto m1 ;

m1:  return ans ;
}

if-else

// file work.c

extern char* nullUser ;
extern char* nullPhone ;
extern char* nullCode ;
extern char* nullCountry ;

char* 
countryName (int d) 
{
  char *ans ;

  ans = findUser   (d) ;  if (!strcmp (ans, nullUser))  return ans ;
  ans = getPhone (ans) ;  if (!strcmp (ans, nullPhone)) return ans ;
  ans = getCode  (ans) ;  if (!strcmp (ans, nullCode))  return ans ; 

  return findByCode (ans) ;
}

exceptions

// file work.c

#include <setjmp.h>

extern char* nullUser ;
extern char* nullPhone ;
extern char* nullCode ;
extern char* nullCountry ;

char* 
countryName (int d) 
{
  char *ans ;

  jmp_buf b ;
  int k = setjmp (b) ;

  if (k == 0) 
  {
    ans = findUser     (d) ; if (!strcmp (ans, nullUser))    longjmp(b, 1) ;
    ans = getPhone   (ans) ; if (!strcmp (ans, nullPhone))   longjmp(b, 2) ;
    ans = getCode    (ans) ; if (!strcmp (ans, nullCode))    longjmp(b, 3) ;
    ans = findByCode (ans) ; if (!strcmp (ans, nullCountry)) longjmp(b, 4) ;
    return ans ; 
  }

  return 
    k == 1 ? nullUser : 
      k == 2 ? nullPhone :
        k == 3 ? nullCode :
          k == 4 ? nullCountry : "unknown error" ; 
}

хаскельнутые

сначала - файл базы данных 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 Codes = C { country :: String, digs  :: String  } deriving (Show)

dbusers = [
    U {uname = "Neo",      uid = 4},
    U {uname = "Morpheus", uid = 2},
    U {uname = "Tom",      uid = 3},
    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 {country = "USA", digs = "123"},
    C {country = "RUS", digs = "456"}
  ]


-- 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

getCountryCode :: String -> Either String String 
getCountryCode 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

main :: IO (Either String String)
main = readLn >>= print . countryName >> main

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

это все. лапидарно. правильная вещь ©