Analizar, no validar

En diciembre, encontré un artículo absolutamente notable en inglés, dedicado al uso del sistema de tipos de idiomas para una clase más amplia de tareas, para aumentar la confiabilidad de las aplicaciones y la facilidad de refactorización. Desafortunadamente, en ese momento estaba demasiado ocupado escribiendo artículos sobre FA, que era extremadamente importante escribir mientras los recuerdos aún están frescos. Pero ahora, cuando hice frente a esta tarea, finalmente pude traducir esta maravillosa nota. El lenguaje original de los ejemplos es Haskell, pero decidí copiarlos a un rast, para un mayor alcance de la audiencia. Sin embargo, el lenguaje aquí no es completamente importante, utilizo los consejos de este artículo en el desarrollo diario en C # y TypeScript completamente "mundanos", por lo que si solo intenta escribir código confiable y compatible, entonces, independientemente del idioma, el artículo estará en el tema.


Gracias por la revisión y asistencia de traducción. Hirrolot, funkill y andreevlex



Durante un período de tiempo bastante largo, luché por encontrar una manera precisa y simple de explicar qué es el diseño impulsado por tipo (en adelante, TypeDD, aprox. Trans. ). Muy a menudo me preguntaron: "¿Cómo se te ocurrió una decisión así?", Pero no tuve una respuesta satisfactoria. Sé con certeza que no se me ocurrió como una visión: tenía un proceso de diseño iterativo que no me obligaba a sacar la arquitectura "correcta" de la nada en este momento, pero hasta ahora no he podido interpretar este proceso para otros.


: JSON , , . , , , TypeDD, , , :


, .


TypeDD


, : TypeDD, , , . , . , , , .



, , , " ?". :


enum Void {}

fn foo(x: i32) -> Void

? , — , .. Void — , , Void. , , :


fn head<T>(xs: Vec<T>) -> T

. ? , - , , :


fn head<T>(xs: Vec<T>) -> T {
    match xs.as_slice() {
        [x, ..] => *x
    }
}

error[E0004]: non-exhaustive patterns: `&[]` not covered
 --> src/lib.rs:2:11
  |
2 |     match xs.as_slice() {
  |           ^^^^^^^^^^^^^ pattern `&[]` not covered
  |

, , , . , , [], . , .. , , , ! , , , ( , . .).



- . , . , " " - , . head, , .



, head , .. : , . , : . , , , , : , , . Rust Option:


fn head<T>(xs: Vec<T>) -> Option<T>

, headNone, , T:


fn head<T>(xs: Vec<T>) -> Option<T> {
    match xs.as_slice() {
        [x, ..] => Some(*x),
        [] => None,
    }
}

, ? , — … .


Option, , , head. . head None, , . , :


fn get_configuration_directories() -> Result<Vec<String>, &'static str> {
    let config_dirs_string = std::env::var("CONFIG_DIRS").map_err(|_| "cannot read env")?;
    let list: Vec<_> = config_dirs_string.split(',').map(|x| x.to_string()).collect();
    if list.is_empty() {
        return Err("CONFIG_DIRS cannot be empty");
    }
    Ok(list)
}

fn main() -> Result<(), &'static str> {
    let config_dirs = get_configuration_directories()?;
    match head(config_dirs) {
        Some(cacheDir) => initialize_cache(cacheDir),
        None => panic!("should never happen; already checked config_dirs is non-empty")
    }
    Ok(())
}

get_configuration_directories , . head main, , Option<&str> None, , , ! :


  1. -, . , , ?


  2. -, . , , , , , .


  3. , , . , get_configuration_directories , , , ? , main, "" , .



. None , get_configuration_directories .
, , .



, head , . , - : , , head , , , . ?


() head .


fn head<T>(xs: Vec<T>) -> T

, . , , : ( — Vec<T>). , head .


, , .
, NonEmptyVec . :


struct NonEmptyVec<T>(T, Vec<T>);

, NonEmptyVecT (, ) Vec<T>. , Vec<T> [], . , head :


fn head<T>(xs: NonEmptyVec<T>) -> T {
    xs.0
}

, , , , . :


fn get_configuration_directories() -> Result<NonEmptyVec<String>, &'static str> {
    let config_dirs_string = std::env::var("CONFIG_DIRS").map_err(|_| "cannot read env")?;
    let list: Vec<_> = config_dirs_string.split(',').map(|x| x.to_string()).collect();
    match non_empty(list) {
        Some(x) => Ok(x),
        None => Err("CONFIG_DIRS cannot be empty")
    }
}

fn main() -> Result<(), &'static str> {
    let config_dirs = get_configuration_directories()?;
    initialize_cache(head(config_dirs));
    Ok(())
}

, main ! , get_configuration_directories. NonEmptyVec Vec non_empty, :


fn non_empty<T>(list: Vec<T>) -> Option<NonEmptyVec<T>>

, Option , None : . , NonEmptyVec, ( !) , . , NonEmptyVec Vec<T> , .


head , :


  • , .


  • , get_configuration_directories , . , main , !



, head , non_empty:


fn old_head<T>(xs: Vec<T>) -> Option<T> {
    non_empty(xs).map(head)
}

, : head . , .



? , — , , . , : , , . :


fn validate_non_empty<T>(xs: Vec<T>) -> Result<(), UserError> {
    if !xs.is_empty() {
        Ok(())
    } else {
        Err(UserError::new("list cannot be empty"))
    }
}

fn parse_non_empty<T>(mut xs: Vec<T>) -> Result<NonEmptyVec<T>, UserError> {
    if !xs.is_empty() {
        let head = xs.remove(0);
        Ok(NonEmptyVec(head, xs))
    } else {
        Err(UserError::new("list cannot be empty"))
    }
}

: , , . : validate_non_empty (), , , parse_non_empty NonEmptyVec<T>, , . , parse_non_empty , validate_non_empty .


: validate_non_empty , parse_non_empty , . , parse_non_empty , , ", ". parse_non_empty. - , ? , , , , parse_non_empty , .


: ? , , , . , — — , - . , , , parse_non_empty : , .


: , , , ! Rust , :



: . - -, , . , , , , , .


, , : , . : - , . , NonEmpty : , .



, , , . , ? , , , ?


, . Ad-hoc , - . 2016 The Seven Turrets of Babel: A Taxonomy of LangSec Errors and How to Expunge Them :


— , , , ; , ( - ), "" .

, :


, . , - , .

, , , , , , , . — , , , — .


, — , , . , , , , "" . , , .


, : , , , . , .


, ,


, . ", , !", , , . "" "", "".


: .


, , , , , - . — , , :


fn check_no_duplicate_keys<K: Eq, V>(xs: &[(K,V)]) { ... }

"" — : . - , , , . , , , HashMap. , HashMap , , .


, , , , , . - , HashMap . , , , . check_no_duplicate_keys:


fn check_no_duplicate_keys<K: Eq, V>(xs: &[(K,V)]) -> HashMap<K,V> { ... }

, !


:


  1. , . , . , , .


  2. , . , . , , , .


    , . - , .



, , , , . , , - . , - !


, :


  • , . bool , ( , , . .). , — , , ,


  • Result<(), Error> . , - , , .


  • . , , , , , , . — -.


  • , , : .


    • . , , , .

  • , " " . , , , , , . (newtype) , - .



, . , error "impossible" - — , , . , , .



, -. , , — ! , .


. , — " " — . , , , . , — ! — . , — .


, , : Type Safety Back and Forth. , . Ghosts of Departed Proofs, , , .


, , , . , — , . , TypeDD, , , , . , , . , — .





, — , .


All Articles