Question

J'ai pensé à certains concepts qui sous-tendent une nouvelle langue. C'était un peu un jouet au début, mais maintenant, je me demande si elle pourrait quelque chose de vraiment méchant. Je poste cette question à Stack Overflow pour voir si cela a été fait avant, et si je peux obtenir des commentaires, des idées, ou d'autres informations.

J'ai commencé à penser à ce surtout après avoir lu la présentation de Jonathan Edward sur de programmation déclarative. Je puis mélangé avec certaines de mes idées anciennes et ce que je l'ai vu dans les langues modernes.

L'idée principale derrière la programmation déclarative est « quoi » par rapport à « comment ». Cependant, je l'ai entendu dire que tant de fois, il semble presque toujours comme le mot « intéressant », où il ne vous dit pas quoi que ce soit, ce qui est frustrant.

La version de Jonathan Edward Dans bien, il a d'abord commencé par souligner href="http://en.wikipedia.org/wiki/Lazy_evaluation". Cela a des conséquences intéressantes, à savoir programmation réactive fonctionnelle (FRP) . Voici un exemple de FRP avec animation (en utilisant une syntaxe je compose):

x as time * 2 // time is some value representing the current time
y as x + (2 * 500)

new Point(x, y)

Voici donc les valeurs changent juste automatiquement si le changement des entrées. Dans l'une de mes langues préférées, D , il y avait une distinction entre « pure » et les fonctions « impurs ». Une pure fonction est une fonction qui avait aucun lien avec le monde extérieur et que d'autres fonctions utilisées pures. Sinon, ce serait impur. Le point est que vous pouvez toujours faire confiance à une pure fonction pour retourner la même valeur pour les arguments donnés.

Je suppose un principe similaire transitif applique ici. Notre impureté est time. Tout touché par time, étant x, ainsi y, et donc new Point(x, y) sont impurs. Toutefois, un avis (2 * 500) est pur. Donc, vous voyez cela indique au compilateur où ses limites. Je pense comme la simplification d'une expression mathématique avec des variables:

(x ^ 2) + 3x + 5
(4 ^ 2) + 3x + 5 = 16 + 3x + 5 = 21 + 3x = 3(7 + x)

En racontant le compilateur ce qui est pur et ce qui est pas, nous pouvons simplifier nos programmes beaucoup. Un autre point est données ou désireux mutables. Jonathan Edward est reconnu comme étant l'entrée mutable et désireux, mais la sortie comme fonctionnelle et paresseux. En fait, donné une nouvelle entrée, le programme a défini un changement d'état atomique , puis sur la sortie serait tout simplement en fonction de l'état actuel . Si vous voulez voir pourquoi cela peut être important, voir la présentation. L'entrée est impur. évaluation paresseuse aide à définir le changement d'état atomique. Jetons un coup d'oeil à la façon dont un programme serait écrit la procédure:

void main ()
{
    String input = "";

    writeln("Hello, world!");
    writeln("What's your name? ");

    input = readln();

    writeln("Hello, %s!", input);
    writeln("What's your friends name? ");

    input = readln();

    writeln("Hello to you too, %s!", input);
}

Ici, le mot-clé bind dit que le code suivant est exécuté si begin change. Le mot-clé mutable dit que l'entrée est pas paresseux, mais désireux. Maintenant, regardons comment un « changement d'état atomique » pourrait représenter.

program:
    mutable step := 0

    bind begin:
        writeln("Hello, world!")
        writeln("What's your name? ")
        ++step

    bind readln() as input when step = 1:
        writeln("Hello, %s!", input)
        writeln("What's your friends name? ")
        ++step

    bind readln() as input when step = 2:
        writeln("Hello to you too, %s!", input)

Maintenant, nous voyons ici quelque chose qui pourrait être rendu plus facile et plus facile à lire, pour le programmeur. Tout d'abord est la variable step laid et comment nous devons augmenter et le tester à chaque fois. Voici un exemple de ce qu'une nouvelle version améliorée pourrait ressembler à:

program:
    bind begin:
        writeln("Hello, world!")
        writeln("What's your name? ")

    bind readln() as input:
        writeln("Hello, %s!", input)
        writeln("What's your friends name? ")
        yield // This just means the program jumps to here instead of at the beginning
        writeln("Hello to you too, %s!", input)
        halt

C'est mieux. Pas parfait, cependant. Mais si je connaissais la réponse parfaite, je ne serais pas ici, non?

Voici un meilleur exemple, en utilisant un moteur de jeu:

class VideoManager:
    bind begin: // Basically a static constructor, will only be called once and at the beginning
        // Some video set up stuff

    bind end: // Basically a static destructor
        // Some video shut down stuff

class Input:
    quitEvent     as handle // A handle is an empty value, but can be updated so code that's bound to it changes.
    keyboardEvent as handle(KeyboardEvent) // This handle does return a value though
    mouseEvent    as handle(MouseEvent)

    // Some other code manages actually updating the handles.

class Sprite:
    mutable x := 0
    mutable y := 0

    bind this.videoManager.updateFrame:
        // Draw this sprite

class FieldState:
    input  as new Input
    player as new Sprite

    bind input.quitEvent:
        halt

    bind input.keyboardEvent as e:
        if e.type = LEFT:
            this.player.x -= 2
        else if e.type = RIGHT:
            this.player.x += 2
        else if e.type = UP:
            this.player.y -= 2
        else if e.type = DOWN:
            this.player.y += 2

Je aime que cela ne nécessite pas callbacks, des événements ou même des boucles ou quoi que ce soit, et les fils sont évidents. Il est plus facile de dire ce qui se passe, et il n'y a pas que le Python comme la syntaxe. Je pense qu'il est le genre de chose comme quand les développeurs de langue ont réalisé qu'il n'y avait que quelques choses que les gens utilisaient des étiquettes et goto »s pour: branches conditionnelles et des boucles. Ils ont donc construit if-then-else, while, et dans les langues, les étiquettes et GOTO se sont dépréciées, et les compilateurs ainsi que les gens pourraient dire ce qui se passait. La plupart de ce que nous utilisons provient de ce processus.

Pour en revenir à des fils, la chose à ce sujet est que les fils sont beaucoup plus souples. Si le compilateur est libre de faire ce qu'il veut parce que nous avons fait plus de dire ce que nous voulons, comment nous voulons faire. Ainsi, le compilateur peut tirer parti des processeurs multi-core et distribués, mais encore pour compenser les plates-formes sans un bon support de filetage.

Il y a une dernière chose que je voudrais mentionner. Et c'est mon point de vue sur les modèles. Ce type était d'un œuf conceptuel qui a commencé à développer comme je l'ai commencé la programmation (il y a environ 2 ans, en fait), puis plus tard a commencé à se fissurer ouverte. Fondamentalement, il était le principe de l'abstraction, mais il étendait plus loin que les classes et objets.

Il a à voir avec la façon dont je percevais une fonction. Par exemple:

int add (int a, int b)
{
    return a + b;
}

D'accord, add a retourné une int, mais que n'a il? Ce genre de ressenti comme une int attente de se produire. Comme un puzzle sans quelques pièces. Il y avait des possibilités limitées, et que certains morceaux en forme, mais quand vous avez terminé, vous avait un produit fini que vous pouvez ensuite utiliser un autre endroit. Ceci est, comme je l'ai dit, le principe de l'abstraction. Voici quelques exemples de ce que je pense sont abstraction + pièces manquantes -> relations concrètes:

  • fonction + arguments -> valeur
  • classe abstraite + méthodes -> classe
  • valeurs classe + instance objet ->
  • modèle + arguments -> fonction ou classe
  • programme + entrée + état -> sortie

Ils sont tous étroitement liés. Il semble que cela pourrait être mis à profit. Mais comment? Encore une fois, voilà pourquoi cela est une question. Mais l'évaluation paresseuse est intéressant ici, puisque vous pouvez passer quelque chose avec ses pièces sont toujours portées disparues à autre chose. Pour le compilateur, il est surtout une question de noms déréférencement jusqu'aux impuretés. Comme mon exemple ci-dessus:

(x ^ 2) + 3x + 5
(4 ^ 2) + 3x + 5 = 16 + 3x + 5 = 21 + 3x = 3(7 + x)

Les plus pièces que vous donnez le compilateur, plus il peut terminer et réduire le programme à son noyau essentiel. Et la fonction add ci-dessus serait résolu au moment de la compilation, automatiquement, puisqu'il repose sur aucune ressource à l'extérieur. Même beaucoup de classes et les objets pourraient être résolus, et d'énormes portions de programmes, en fonction de la façon dont le compilateur smart est.

C'est tout pour l'instant. Si vous avez vu des exemples de ces choses déjà faites, je voudrais voir. Et si vous avez des idées, l'innovation, les ressources ou dans les commentaires, je vous en serais reconnaissant aussi.

Était-ce utile?

La solution

Vous voulez certainement voulez jeter un oeil à la Haskell langage de programmation.

Haskell est extrêmement déclarative, les bibliothèques de programmation-évaluation paresseuse est intégrée et même réactifs fonctionnels existent. Mais plus particulièrement, Haskell est purement fonctionnel , tout savoir, vraiment tout, est pur .

La question est de savoir comment Haskell accord avec les impuretés nécessaires qui se posent dans une IO.

Les crises de réponse assez bien aux pensées que vous présentées. Haskell utilise une construction mathématique appelée monades qui représentent essentiellement un calcul produisant une valeur aussi d'un bind de fonction (>>= comme un opérateur infixe), que les séquences de ces calculs.

Prenons donc quelques exemples IO: lire une ligne et la sortie de votre nom ... Même IO est pur, de sorte que vous ne pouvez pas simplement lancer quelque chose. Au lieu de cela, vous construisez un plus grand calcul IO

do
    putStr "Enter your name: "
    name <- getLine
    putStrLn ("Hello " ++ name)

semble tout à fait impératif, mais sous le capot, il est juste syntaxe

(putStr "Enter your name: ") >>
(getLine >>= \name ->
 putStrLn ("Hello " ++ name))

Maintenant, vous pouvez définir cette bind / >>= pour types arbitraires de calculs de quelque façon que vous le souhaitez. Donc, dans tout ce fait, vous avez parlé peut être réalisé de cette façon -. Même FRP

Juste essayer à la recherche de monades ou Haskell ici sur Stackoverflow; il y a eu beaucoup de questions à ce sujet. Et après tout, il est encore tout type vérifié et donc correct peut être exécutée par le compilateur.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top