[JAVA] Essayez de faire un programme d'addition en plusieurs langues

introduction

Au début, j'ai résumé la programmation orientée objet et ses fonctionnalités, mais je n'ai pas pu bien le faire et j'ai abandonné.

Donc, au lieu de cela, j'ai pensé qu'il serait préférable de créer une tâche simple, de la programmer concrètement et de la comparer, alors j'ai décidé de commencer par un simple programme d'addition.

Comme langage, j'ai choisi Pascal (Pascal standard) comme langage orienté procédure, Java comme langage orienté objet et Haskell comme langage fonctionnel.

Ce choix de langue est complètement un passe-temps. Je ne peux pas bien le dire, mais j'aime le langage à paradigme unique, à typage statique, qui a tendance à avoir une longue syntaxe et qui semble un peu "spongieux".

L'addition ne calcule pas simplement en une seule ligne, mais accepte les entrées de l'utilisateur et définit la fonction comme suit.

1.Tout d'abord, le message "Entrez un numéro. Il se termine par une ligne vide." S'affiche.
2. 「>S'affiche et attend une entrée. Si vous entrez un nombre et coupez une ligne, il sera enregistré
3.encore">S'affiche et attend une entrée. Répétez jusqu'à un saut de ligne sans entrer de caractères.
4.Si un saut de ligne vide se produit, le résultat de l'addition de la somme de tous les nombres saisis jusqu'à présent est affiché. "Le total est xxx" s'affiche.
5.Ignorez les entrées qui incluent des caractères autres que des nombres.

En fait, je pense qu'un échantillon un peu plus compliqué fera ressortir l'individualité de chaque langue, mais la première étape est la suivante.

L'image réelle de l'opération est comme ceci.

Veuillez saisir le numéro. Il se termine par une ligne vierge.
>10
>20
>4
>
Le total est de 34.

Cet article est destiné aux débutants qui ont appris un langage de programmation et peuvent comprendre le branchement conditionnel et le traitement en boucle.

Implémentation en Pascal

Considérons ici le Pascal standard. Le Pascal standard a peu de fonctionnalités et ne peut pas être compilé de manière fractionnée, mais je pense qu'il convient toujours à l'apprentissage de la programmation, en particulier les bases des algorithmes d'apprentissage.

Tout d'abord, envisagez de mettre en œuvre la routine principale comme suit:


program CalcSumApp;

type
  ItemPtr = ^Item;
  Item = 
    record
      next: ItemPtr;
      text: ShortString;
    end;

//Définition de diverses fonctions

var
  lines : ItemPtr;
  sum : Integer;

begin
  writeln('Veuillez saisir le numéro. Il se termine par une ligne vierge.');
  lines := readLines();
  sum := sumOfLines(lines);
  writeln('Le total est' + toStr(sum) + 'est.');
  disposeAll(lines);
end.

Tout d'abord, nous définissons un pointeur appelé ItemPtr. En fait, en Pascal standard (Pascal ISO 7185), un tableau de longueur variable ne peut pas être utilisé, nous définissons donc ici un Node qui ne peut stocker qu'une seule valeur numérique appelée Item et la saisir sous la forme d'un pointeur. Modifié pour stocker la valeur numérique.

La routine principale (la partie ci-dessous begin) ressemble à ceci:

Le message s'affiche sur la première ligne et la valeur numérique (plusieurs lignes) est acceptée sur la deuxième ligne. Ensuite, sur la 3ème ligne, le total des valeurs numériques saisies est calculé, et sur la 4ème ligne, le résultat est affiché. toStr est une fonction qui convertit un entier en chaîne, mais ce n'est pas non plus dans le pascal standard, donc il est implémenté dans le programme. La cinquième ligne libère de la mémoire. Vous devez relâcher le pointeur vous-même lorsque vous avez terminé.

Maintenant, considérons l'implémentation de readLines dans la partie d'entrée.


function readLines(): ItemPtr;
var 
  result: ItemPtr;
  prevItemPtr: ItemPtr;
  currItemPtr: ItemPtr;
  line: ShortString;
begin
  result := nil;
  prevItemPtr := nil;
  while true do
  begin
    write('>');
    readln(line);
    if line <> '' then 
    begin
      if prevItemPtr = nil then
      begin
        new(prevItemPtr);
        prevItemPtr^.text := line;
        prevItemPtr^.next := nil;
        result := prevItemPtr;
      end
      else 
      begin
        new(currItemPtr);
        currItemPtr^.text := line;
        currItemPtr^.next := nil;
        prevItemPtr^.next := currItemPtr;
        prevItemPtr := currItemPtr;
      end;
    end   
    else
      break;
  end;
  readLines := result;
end;

Entourez le tout dans une boucle while et faites-en un format qui se répète jusqu'à ce qu'une condition (entrée de saut de ligne vide) soit satisfaite.

readln (line) est la partie qui reçoit l'entrée de caractères.

Seule la première fois est spéciale et conserve la valeur saisie dans prevItemPtr. new (prevItemPtr) est une instruction pour allouer une zone dans la mémoire du tas, y stocke la valeur numérique d'entrée et la sauvegarde dans le résultat (result). A partir de la deuxième fois, la valeur saisie est conservée dans currItemPtr. Ensuite, la valeur numérique saisie est stockée et référencée à partir du précédent prevItemPtr. Enfin, mettez à jour currItemPtr en tant que nouveau prevItemPtr.

Vient ensuite la fonction sumOfLines qui calcule l'addition.

function sumOfLines(lines: ItemPtr): Integer;
var
  a : Integer;
  v : Integer;
  err: Boolean;
begin
  a := 0;
  while lines <> nil do
  begin
    err := false;
    v := toInt(lines^.text, err);
    if not err then
      a := a + v;
    lines := lines^.next;
  end;
  sumOfLines := a;
end;

Cela convertit la chaîne en un entier et les ajoute tout en vérifiant les lignes ligne par ligne. La fonction toInt qui convertit une chaîne de caractères en entier est également définie dans le programme car elle n'est pas dans le Pascal standard. De plus, lorsqu'une chaîne de caractères autre qu'une valeur numérique arrive, elle est jugée par le deuxième argument err afin de ne pas provoquer d'erreur. (Par conséquent, ce deuxième argument est un appel de référence)

L'ensemble du programme ressemble à ceci:

program CalcSumApp;

type
  ItemPtr = ^Item;
  Item = 
    record
      next: ItemPtr;
      text: ShortString;
    end;

function toInt(str: ShortString; var err: Boolean): Integer;
var
  i : Integer;
  n : Integer;
  r : Integer;
begin
  r := 0;
  for i := 1 to ord(str[0]) do
  begin
    n := Ord(str[i]);
    if (n < Ord('0')) or (n > Ord('9')) then 
      begin
        err := true;
        break;
      end;
    r := r * 10 + n - Ord('0');
  end;
  toInt := r;
end;

function toStr(n: Integer): ShortString;
var
  m : Integer;
  s : ShortString;
begin
  s := '';
  while n > 0 do
  begin
    m := n mod 10;
    n := n div 10;
    s := chr(m + ord('0')) + s;
  end;
  if s = '' then
    s := '0';
  toStr := s;
end;

procedure disposeAll(ptr: ItemPtr);
begin
  if ptr <> nil then
  begin
    disposeAll(ptr^.next);
  end;
end;

function readLines(): ItemPtr;
var 
  result: ItemPtr;
  prevItemPtr: ItemPtr;
  currItemPtr: ItemPtr;
  line: ShortString;
begin
  result := nil;
  prevItemPtr := nil;
  while true do
  begin
    write('>');
    readln(line);
    if line <> '' then 
    begin
      if prevItemPtr = nil then
      begin
        new(prevItemPtr);
        prevItemPtr^.text := line;
        prevItemPtr^.next := nil;
        result := prevItemPtr;
      end
      else 
      begin
        new(currItemPtr);
        currItemPtr^.text := line;
        currItemPtr^.next := nil;
        prevItemPtr^.next := currItemPtr;
        prevItemPtr := currItemPtr;
      end;
    end   
    else
      break;
  end;
  readLines := result;
end;

function sumOfLines(lines: ItemPtr): Integer;
var
  a : Integer;
  v : Integer;
  err: Boolean;
begin
  a := 0;
  while lines <> nil do
  begin
    err := false;
    v := toInt(lines^.text, err);
    if not err then
      a := a + v;
    lines := lines^.next;
  end;
  sumOfLines := a;
end;

var
  lines : ItemPtr;
  sum : Integer;

begin
  writeln('Veuillez saisir le numéro. Il se termine par une ligne vierge.');
  lines := readLines();
  sum := sumOfLines(lines);
  writeln('Le total est' + toStr(sum) + 'est.');
  disposeAll(lines);
end.

Implémentation en Java

En Java, implémentons-le avec deux classes, la classe CalcSumApp et la classe CalcSum. Le premier est la classe CalcSumApp pour l'ensemble de l'application.


public class CalcSumApp {
  public static void main(String args[]) {
    CalcSum cs = new CalcSum();
    CalcSumApp app = new CalcSumApp();
    app.start(cs);
  } 

  public void start(CalcSum cs) {
    System.out.println("Veuillez saisir le numéro. Il se termine par une ligne vierge.");
    cs.readLines();
    int sum = cs.getSum();
    System.out.println("Le total est" + String.valueOf(sum) + "est.");
  }
}

Dans la fonction main, créez une instance de la classe CalcSumApp et de la classe calcSum et appelez la méthode start.

Le contenu de la méthode start est presque le même que celui de la routine principale de Pascal, mais ils ne gèrent pas directement les données, ils n'opèrent que des objets de la classe CalcSum.

Ensuite, la classe CalcSum ressemble à ceci:

class CalcSum {
  List<String> list;

  CalcSum () {
    list = new ArrayList<String>();
  }

  public void readLines() {
    BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
    String line;
    try {
      do {
        System.out.print('>');
        line = input.readLine();
        if ("".equals(line)) {
          break;
        }
        list.add(line);
      } while (true);
    } catch (IOException e) {

    }
  }

  public int getSum() { 
    int sum = 0;
    for (String s : list) {
      try {
        sum += Integer.valueOf(s).intValue();
      } catch (NumberFormatException e) {

      }
    }
    return sum;
  }
}

La méthode readLines qui accepte les entrées de la console et la méthode getSum qui calcule la somme sont définies. Le contenu est presque le même que la fonction readLines et la fonction sumOfLines dans pascal. Cependant, les données numériques saisies (liste) sont conservées en tant que variable d'instance de la classe CalcSum.

L'ensemble du programme ressemble à ceci: Comparé à Pascal, il est plus propre car il n'y a pas de processus de conversion tel que toInt ou toStr, ou de processus tel que disposeAll of memory release, et c'est bien que la liste soit contenue dans CalcSum. (Bien qu'il puisse être préférable de le rendre `privé ')

import java.util.Scanner;
import java.util.List;
import java.util.ArrayList;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.IOException;
import java.lang.NumberFormatException;

class CalcSum {
  List<String> list;

  CalcSum () {
    list = new ArrayList<String>();
  }

  public void readLines() {
    BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
    String line;
    try {
      do {
        System.out.print('>');
        line = input.readLine();
        if ("".equals(line)) {
          break;
        }
        list.add(line);
      } while (true);
    } catch (IOException e) {

    }
  }

  public int getSum() {
    int sum = 0;
    for (String s : list) {
      try {
        sum += Integer.valueOf(s).intValue();
      } catch (NumberFormatException e) {

      }
    }
    return sum;
  }
}

public class CalcSumApp {
  public static void main(String args[]) {
    CalcSum cs = new CalcSum();
    CalcSumApp app = new CalcSumApp();
    app.start(cs);
  } 

  public void start(CalcSum cs) {
    System.out.println("Veuillez saisir le numéro. Il se termine par une ligne vierge.");
    cs.readLines();
    int sum = cs.getSum();
    System.out.println("Le total est" + String.valueOf(sum) + "est.");
  }
}

Comme c'est facile dans cet exemple, je pense qu'il est possible d'implémenter CalcSum comme un objet immuable, mais en général, dans la programmation orientée objet, je pense que les objets qui peuvent être immuables sont limités, donc je n'aborderai pas l'implémentation qui le rend immuable. fait.

Implémentation dans Haskell

Chez Haskell, la routine principale est à peu près la même et ressemble à ceci:

  main :: IO ()
  main = do
    hSetBuffering stdout NoBuffering
    putStrLn "Veuillez saisir le numéro. Il se termine par une ligne vierge."
    lines <- readLines getLines
    list <- sequence lines
    let s = sum list
    putStrLn $ "Le total est" ++ (show s) ++ "est."

La partie hSetBuffering stdout NoBuffering, comme indiqué dans les commentaires de cet article, était que sans elle, la mise en mémoire tampon ne garantirait pas que les entrées et les sorties seraient dans l'ordre attendu. (Merci à @igrep)

getLines est une liste qui reçoit un nombre infini de chaînes et est définie comme suit.


  getLines :: [IO String]
  getLines = do
    repeat $ putStr ">" >> getLine

repeat crée une liste infinie. En d'autres termes

repeat x = [x x x x .... x ... ]

C'est comme ça. C'est une caractéristique du traitement des délais de Hakell qu'une telle liste infinie peut être gérée, et je voulais l'utiliser comme ça.

readLines est le processus de découpe de la pièce jusqu'à ce qu'une ligne vide soit entrée, et se présente comme suit.


  readLines :: [IO String] -> IO [IO Int]
  readLines [] = return []
  readLines (l:ls) = do
    v <- l :: IO String
    if v == ""
      then return []
    else do
      ll <- readLines ls
      case readMaybe v of 
        Just x -> return $ (return x):ll
        Nothing -> return ll

Si le premier élément du tableau est un caractère vide, c'est tout. Autrement, Convertissez le premier élément en une valeur numérique (readMaybe), et s'il peut être converti, ajoutez le converti (retroprocédé) et renvoyez-le, et s'il ne peut pas être converti, convertissez le reste (traité récursivement) Est de retour seulement.

  list <- sequence lines 

C'est un peu déroutant ici, mais je convertis un tableau IO en un tableau IO et j'en extrait son contenu. Ainsi, «list» n'est qu'un tableau de nombres.

À l'origine ici

  list <- mapM (>>= return) lines

Cependant, comme indiqué dans le commentaire, il peut être résolu en un seul coup avec squence, donc je l'ai changé.

Et le calcul du total se fait ensuite.

   let s = sum list

(Je vais omettre l'histoire de l'évaluation parce que ma compréhension était erronée.)

L'ensemble du programme ressemble à ceci: La conversion des monades est un peu gênante, et contrairement à Java, la variable lines est gérée directement, mais en utilisant la syntaxe do, elle peut être décrite comme pascal.

module CalcSumApp where

  import Text.Read
  import System.IO
          
  getLines :: [IO String]
  getLines = do
    repeat $ putStr ">" >> getLine
    
  readLines :: [IO String] -> IO [IO Int]
  readLines [] = return []
  readLines (l:ls) = do
    v <- l :: IO String
    if v == ""
      then return []
    else do
      ll <- readLines ls
      case readMaybe v of 
        Just x -> return $ (return x):ll
        Nothing -> return ll
  
  main :: IO ()
  main = do
    hSetBuffering stdout NoBuffering
    putStrLn "Veuillez saisir le numéro. Il se termine par une ligne vierge."
    lines <- readLines getLines
    list <- sequence lines
    let s = sum list
    putStrLn $ "Le total est" ++ (show s) ++ "est."

Bonus Haskell Partie 2

Haskell a également essayé de créer un type de données et de l'encapsuler de manière orientée objet. Je ne pense pas que ce soit pratique, mais ...

La routine principale est


  main :: IO ()
  main = do
    hSetBuffering stdout NoBuffering
    putStrLn "Veuillez saisir le numéro. Il se termine par une ligne vierge."
    calcSum <- newCalcSum   -- calcSum = new CalcSum()
    inputStrings calcSum    -- calcSum.inputString()
    sum <- getSum calcSum   -- sum = calcSum.getSum()
    putStrLn $ "Le total est" ++ (show sum) ++ "est."

Cela ressemble à ceci, et je pense que c'est plus proche de Java. Dans tout le code


module CalcSumApp2 where
  import Text.Read
  import Control.Monad
  import Data.IORef
  import Data.Maybe
  import System.IO

  data CalcSum = CalcSum { getStrings :: IORef [String] }

  newCalcSum :: IO CalcSum
  newCalcSum = do
    ref <- newIORef []
    return $ CalcSum ref
  
  inputStrings :: CalcSum -> IO ()
  inputStrings calcSum = do
    let truncateStrings :: [IO String] -> IO [String]
        truncateStrings [] = return []
        truncateStrings (x:xs) = do
        s <- x
        if s == "" 
          then 
            return []
          else do
            l <- truncateStrings xs
            return $ (:l) $! s            -- strict evaluation of s corresponding to `return (s:l)`

    list <- truncateStrings $ repeat $ putStr ">" >> getLine
    writeIORef (getStrings calcSum) list  -- calcSums.strings = list

  getSum :: CalcSum -> IO Int
  getSum calcSum = do
    list <- readIORef (getStrings calcSum) :: IO [String] -- list = calcSum.strings 
    let nums = catMaybes $ readMaybe <$> list :: [Int] 
    return $ sum nums

  main :: IO ()
  main = do
    hSetBuffering stdout NoBuffering
    putStrLn "Veuillez saisir le numéro. Il se termine par une ligne vierge."
    calcSum <- newCalcSum   -- calcSum = new CalcSum()
    inputStrings calcSum    -- calcSum.inputString()
    sum <- getSum calcSum   -- sum = calcSum.getSum()
    putStrLn $ "Le total est" ++ (show sum) ++ "est."
  

Ce que je voulais dire ici, c'est que l'objet (comme la chose) est ʻIORef. Je pense que les objets n'ont rien à voir avec IO en premier lieu, mais dans mon esprit, les objets sont des choses qui allouent une zone dans la mémoire du tas pour lire et écrire (une image comme DB) séparément de l'application, donc ʻIORef Je pensais que ça viendrait bien.

Les objets dans les langages orientés objet ne sont pas seulement de type IORef (partagés et modifiables), mais également des objets non partagés, des objets immuables, des objets immuables et sans côtés (comme aucune entrée / sortie IO) et des effets secondaires. Je pense qu'il y a diverses choses telles que des objets volumineux (objets qui enveloppent le traitement qui interagit avec le serveur externe), mais je ne pouvais pas bien y penser, donc je vais simplement présenter cet exemple ici. Je le garderai.

Impressions

Le Pascal standard a peu de fonctionnalités et vous devez implémenter vous-même toInt ou toStr, ou vous devez libérer la mémoire vous-même, mais ce processus (lourd) est fait. Quand je l'écris, j'aime me sentir comme "Oh, je programme". J'ai l'impression de jouer avec une voiture manuelle au lieu d'une voiture automatique. Ces jours-ci, Go est comme ça.

Bien que Java ait été critiqué de diverses manières, je pense que c'est un bon langage facile à utiliser. Je pense que le langage de programmation orienté objet est plus adapté à la méta-programmation comme Ruby et à la création dynamique d'objets comme JavaScript, mais il y a un sentiment de sécurité que la classe est déterminée statiquement. Ça m'a l'air bien. J'aime Java 1.5 ou plus, et c'est dommage que cela se complique avec tant d'autres paradigmes.

Haskell a beaucoup à étudier et a du mal, mais je suis très heureux quand cela fonctionne. Il y a beaucoup de fonctions et c'est difficile à comprendre et à retenir, mais on a l'impression que c'est un gros problème quand on sait comment l'utiliser, et c'est bien d'avoir une solution statique. Je pense qu'il est bon de faire attention au type.

en conclusion

Dans cet exemple simple, cela ne change pas grand-chose dans aucune implémentation, mais je me suis demandé s'il y avait encore des fonctionnalités de chaque langage.

Le nombre de langages de programmation de nos jours est multi-paradigme, c'est pourquoi je pense qu'il est important d'apprendre les bases des langages à paradigme unique.

Si vous avez des erreurs ou des insuffisances, veuillez commenter.

Recommended Posts

Essayez de faire un programme d'addition en plusieurs langues
Essayez d'implémenter l'ajout n-aire en Java
J'ai essayé de développer une application en 2 langues
J'ai essayé de faire une demande en 3 mois d'inexpérimenté
[swift5] Essayez de créer un client API avec différentes méthodes
CompletableFuture Getting Started 2 (Essayez de faire CompletableFuture)
Créer un compteur FPS avec Swift
Essayez de faire un simple rappel
Essayez d'implémenter Yuma dans Ruby
Essayez une expression If en Java
Essayez d'implémenter Yuma en Java
CompletableFuture Getting Started 2 (Essayez de faire CompletableFuture)
Essayez de créer un itérateur qui puisse être vu
Interface Essayez de créer un problème Java TypeScript 7-3
Essayez de résoudre Project Euler en Java
Facile à créer Slack Bot avec Java
Je veux créer une application ios.android
Essayez d'ajouter du texte à une image avec Scala en utilisant la bibliothèque standard de Java
NLP4J [006-034b] Essayez de faire en sorte que l'annotateur de 100 traitements de langage frappe # 34 "A B" avec NLP4J
Comment faire une méthode de jugement pour rechercher n'importe quel caractère dans le tableau
Je souhaite envoyer un e-mail en Java.
Essayez de créer un babillard en Java
Deuxième décoction: essayez une expression If en Java
Comportement incrémenté Essayez de créer un problème Java TypeScript 3-4
Je voulais que (a == 1 && a == 2 && a == 3) vrai en Java
Opération de chaîne de caractères Essayez de changer le problème Java en TypeScript 9-3
Comment résoudre les problèmes d'expression en Java
Comment créer un fichier exécutable dans Maven
Comment créer un lecteur de musique Android imposant