IPB

Bienvenue invité ( Connexion | Inscription )

2 Pages V   1 2 >  
Reply to this topicStart new topic
> [Swift] On tente ?, L'histoire se répète...
Options
Jaypee
posté 16 Jul 2014, 06:30
Message #1


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 486
Inscrit : 29 Aug 2002
Membre no 3 340



Chez les Développeurs Apple, l'histoire bégaye...

Il y a eu l'origine, le 68K, la ToolBox initiale, la première API autour de la boucle principale et le getNextEvent, qui a évolué jusqu'à une cetaine maturité avec CodeWarrior et PowerPlant. Sur cette toolbox a été développée une version de SmallTalk, dont la syntaxe à influencé Objective-C, avec les noms de fonction segementés par paramètre, et la structure des messages émetteur message receveur.

Il y a eu un passage presque oublié avec Dylan, sur le Newton, ancêtre de la tablette.

Puis Apple a repris la main, OSX et Cocoa sont arrivés, et ont évolué en se débarrassant petit à petit des aspects les plus difficiles, la gestion de mémoire maintenant simplifiée avec ARC, et en introduisant plus de "magie sous le capot" avec les KVC, KVO...

Enfin Apple récidive avec Swift. Sur le papier, c'est la bonne direction, un langage plus moderne, et enrichi de l'expérience des autres langages. Il représente le club encore fermé de la FRP, "Functional Reactive Programming", à la confluence de la FP et du Réactif.

Je ne suis pas un développeur avec une base de code à faire vivre, je n'ai aucune histoire en héritage, je n'ai donc aucune réticence à tenter l'aventure.

Mais vous, quelle est votre perspective face à cette nouvelle évolution technologique ?

J-P
PS: XCode 6 Bêta est dispo pour essayer Swift

Ce message a été modifié par Jaypee - 16 Jul 2014, 14:24.
Go to the top of the page
 
+Quote Post
Jaypee
posté 17 Jul 2014, 17:17
Message #2


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 486
Inscrit : 29 Aug 2002
Membre no 3 340



Pour ceux qui aurait besoin d'un peu de Français pour se faire une idée, voici une traduction partielle http://www.swiftcode.fr/ et je vais essayé en quelques lignes de montrer quels sont les enjeux et les problèmes que Swift veut prendre en compte.

- Swift est construit sur la base LLVM qui est une sorte de "compilateur de compilateur", qui si on ne le customise pas produit un compilateur C en 3 lignes: analyser le source, produire le code machine et relier les modules entre eux.

Apple l'a customisé pour une nouvelle grammaire, Swift, mais le code produit est de la même qualité que celle du compilateur C/ObjC/C++.

- Swift est fonctionnel:
- Il insiste sur la différence entre constante et variable. C'est très important pour la programmation parallèle, il est important de savoir qu'une valeur ne change pas, même si un second fil (thread) éxécute le même code en parallèle.
Dans les langages où cela n'est pas disponible, on peut commencer un bloc de code avec une certaine valeur de x qu'on pense être à 1, mais un autre fil l'éxécute avec un x=2, au moment où le premier fil éxécute x++, au lieu d'obtenir 2, il aura 3. Or aujourd'hui, le matériel est de plus en plus à l'aise avec le paralléllisme, grâce à la multiplication des coeurs de processeur.

- Les fonctions sont des valeurs comme les autres.
On peut utiliser la valeur sans la nommer comme la chaine "Hello, World!" dans le C printf("Hello, World!\n");
On peut la passer dans une fonction
On peut la retourner d'une fonction. comme String bonjour(String nom) { return String.format("Bonjour %s !", nom) ;}

On peut ainsi rendre plus abstraite certaines fonctions et les customiser par des fonctions passées en argument: Par exemple, la somme d'une suite de nombres ou une factorielle, c'est la même chose, dans un cas on utilise l'addition, et l'autre on multiplie. Cette fonction très générique s'appelle souvent un mapReduce ou même mapFilterReduce. Elle résoudra aussi bien la factorielle que la somme des carrés des nombres impairs... Moins de code peut résoudre plus de problèmes grâce à cette abstraction accrue.

- Swift est réactif:
- Les interfaces graphiques sont construites sur un "pattern" Observable/Observateur
- Observables: la souris, le clavier, le réseau
- Observateur: Le contrôleur de l'appli et sa boucle d'événements.

- Le modèle réactif est l'évolution la plus actuelle, qui doit faire face à une forte demande comme ce qui se passe sur un réseau social. Il utilise des acteurs et des messages.

Au bilan:
- Peut résoudre des problèmes plus complexes par une abstraction plus naturelle par rapport à une abstraction par des objets artificiels
- Très à l'aise avec le parallélisme.
- Prêt pour une forte demande (réactif)

Voilà, j'espère avoir été assez clair,
J-P

Ce message a été modifié par Jaypee - 17 Jul 2014, 17:23.
Go to the top of the page
 
+Quote Post
No6
posté 17 Jul 2014, 17:57
Message #3


Oui ?
*****

Groupe : Membres
Messages : 3 889
Inscrit : 24 Jun 2003
Lieu : BZH
Membre no 8 224



@ Jaypee

Perso j'avais misé beaucoup sur OpenDoc; même encore aujourd'hui la pilule est amère. huh.gif


--------------------
"Je sais que vous croyez comprendre ce que vous pensez que j'ai dit, mais je ne suis pas sûr que vous réalisiez que ce que vous avez entendu n'est pas ce que je pense."
(Alan Greenspan)
Go to the top of the page
 
+Quote Post
Jaypee
posté 17 Jul 2014, 20:15
Message #4


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 486
Inscrit : 29 Aug 2002
Membre no 3 340



Je sais, c'est le dilemme... La perrennité des révolutions...

Avec l'accélération de l'évolution, Swift bien que neuf, ne part pas de zéro, beaucoup de langages similaires ont été créés ces dernières années : Clojure, Ceylon, Scala, Haskell, Java 8... Scala étant probablement le plus mûr au sens de l'industrie, puisqu'il a déjà sauvé les baleines de Twitter, et fait vivre Facebook. Le choix du fonctionnel ne fait plus débat. Il fait le boulot...

Java 8 a fait le choix de l'évolution dans la continuité, mais au prix d'un pragmatisme auquel il faut adhérer :
- Au départ, on a des interfaces (des APIs) qui dissocient clairement la signature de la fonction (liste des arguments et leur type) de son instrumentation (le code qui fait le boulot)
- Pour aller vers le fonctionnel, il faut ajouter des signature nouvelles, mais ce faisant on romp le contrat avec les bibliothèques externes qui fournissaient le code pour l'ancienne interface, elles sont défaillantes si les nouvelles interfaces sont utilisées avec le code ancien...
- Solution pragmatique : Les interfaces peuvent contenir du code par défaut pour les signatures nouvelles.
On peut aimer ou pas...

Swift permet d'évoluer, sans ce genre de pragmatisme, il offre une base nouvelle, mais qui compose bien avec l'ancien.

L'abstraction est un aspect important. Pour répondre à une demande très importante, on doit raisonner sur des ensembles infinis. Avec le fonctionnel, on peut développer ce raisonnement sans effecteur le vrai travail, donc sans se soucier de capacité de stockage ou de performance... jusqu'à ce qu'on demande à voir. Là il faut passer à la caisse. C'est la notion de "paresse".

Enfin, l'abstraction, c' est aussi le retour à l'algèbre et aux maths "classiques". Le problème des Tours de Hanoï, certes très académique sert souvent à introduire la récursivité, et le raisonnement abstrait associé:Supposons qu'on sache déplacer n-1 disques de A vers C, il suffit de déplacer le n-ième disque de A vers B, puis de déplacer n-1 disques de C vers B.

Ce genre de raisonnement est de retour !

J-P

Ce message a été modifié par Jaypee - 17 Jul 2014, 20:17.
Go to the top of the page
 
+Quote Post
noop
posté 17 Jul 2014, 22:56
Message #5


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 964
Inscrit : 3 Nov 2005
Membre no 49 239



Citation (No6 @ 17 Jul 2014, 18:57) *
@ Jaypee

Perso j'avais misé beaucoup sur OpenDoc; même encore aujourd'hui la pilule est amère. huh.gif


moi aussi sous OS/2

Code
Dans les langages où cela n'est pas disponible, on peut commencer un bloc de code avec une certaine valeur de x qu'on pense être à 1, mais un autre fil l'éxécute avec un x=2, au moment où le premier fil éxécute x++, au lieu d'obtenir 2, il aura 3. Or aujourd'hui, le matériel est de plus en plus à l'aise avec le paralléllisme, grâce à la multiplication des coeurs de processeur.


euuh....les semaphores ou section critique c'est pas fait pour les chiens ! voila piurquoi les developpeurs ne sont pas capable d'utiliser les cores

Ce message a été modifié par noop - 17 Jul 2014, 22:59.
Go to the top of the page
 
+Quote Post
Jaypee
posté 18 Jul 2014, 06:28
Message #6


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 486
Inscrit : 29 Aug 2002
Membre no 3 340



Les solutions techniques existent mais ne font que déplacer le problème d'un cran. Les surveillants sont une resource rare, qu'il faut partager et si les surveillants doivent être partagés, qui surveillera les surveillants...

J'ai continué à faire le tour du proprio... la peinture n'est pas sèche, certains exemples du manuel ne fonctionnent pas.

J'ai cité la récursivité... mal utilisée, elle consomme de la pile, qui peut exploser si on va chercher trop loin, on risque "StackOverflow". La solution existe en utilisant un accumulateur de résultat.
Exemple de factorielle "naïve":
Code
func fact(n: Int) -> Int {
    switch n {
        case 0: return 1
        default: return n * fact(n - 1)
    }
}


L'appel récursif est attendu pour terminer une multiplication (recursion non terminale), donc pour factorielle 50, il y a 50 multiplications en attente, et pour 100, et pour 1000...
L'idée est d'utiliser une autre fonction qui va utiliser un argument supplémentaire pour recevoir cette multiplication:
Code
    func fact0(n: Int, accu: Int) -> Int {
        switch n {
            case 0: return accu
            default: return fact0(n - 1, n * accu)
        }
    }

L'inconvénient, sa syntaxe est moins naturelle que fact(n) c'est fact0(n, 1). L'idée est que fact(n) est définie comme fact0(n, 1) et de cacher fact0 dans fact. C'est une fonction "enchâssée"
Code
func fact(n: Int) -> Int {
    func fact0(n: Int, accu: Int) -> Int {
        switch n {
            case 0: return accu
            default: return fact0(n - 1, n * accu)
        }
    }
    return fact0(n, 1)
}


Malheureusement, ça ne fonctionne pas encore comme documenté.

J-P

Ce message a été modifié par Jaypee - 18 Jul 2014, 06:31.
Go to the top of the page
 
+Quote Post
Slumb
posté 18 Jul 2014, 10:52
Message #7


Macbidouilleur d'argent !
***

Groupe : Membres
Messages : 782
Inscrit : 11 Sep 2005
Membre no 45 692



Merci J-P pour ces retours et le lien "fr". Pour ma part, je continu sur Objective-C encore pour quelques temps et je me lancerais à fond sur Swift dans quelques mois.


--------------------
iMac 27" - MBP 15"
PC ASUS Z97 WIFI + Bluetooth - Intel Core i7-4790K CPU 4,00GHz - GeForce 980 GTX ZOTAC 4Go - 16Go RAM - SSD Crucial
Bluetooth Device (Personal Area Network)
Bluetooth Device (RFCOMM Protocol TDI)
Carte réseau Broadcom 802.11ac
Intel Ethernet Connection I218-V
Go to the top of the page
 
+Quote Post
darenzana
posté 19 Jul 2014, 09:53
Message #8


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 1 745
Inscrit : 13 Nov 2006
Membre no 72 823



Bonjour,
je ne comprends pas l'intérêt de ta fonction fact0, par rapport à fact... La pile est autant sollicitée dans les 2 cas.


--------------------
Macbook Pro 15" Core 2 Duo 2.33GHz, 3Go RAM, Mac OS X 10.6.8 | Macbook Air 13" mi-2011 Core i5, Mac OS X 10.8
NAS Synology DS-110+
iPhone 6 silver 64Go - forfait SFR Red 3Go
Go to the top of the page
 
+Quote Post
Jaypee
posté 19 Jul 2014, 12:54
Message #9


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 486
Inscrit : 29 Aug 2002
Membre no 3 340



Non, comme l'appel récursif est isolé (récursion terminale ou tail-récursion), pas composé avec une autre opération, le calcul se fait complètement et la pile peut être nettoyée.
Si on représente la pile couchée et avec empilage par la droite:
t0: fact(n)
t1: n * fact(n - 1)
t2: n * n - 1 * fact(n - 2)
On voit que la pile grandit à chaque appel

t0: fact0(n, 1)
t1: fact0(n - 1, n)
t2: fact0(n - 2, n * n - 1)
On voit que la pile est constante

Une fois qu'on a réussi cette étape, l'étape suivante est de transformer la récursion en itération.
C'est l'un des "patterns" de la programmation.

J-P

Ce message a été modifié par Jaypee - 19 Jul 2014, 12:56.
Go to the top of the page
 
+Quote Post
Jaypee
posté 19 Jul 2014, 13:31
Message #10


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 486
Inscrit : 29 Aug 2002
Membre no 3 340



L'un des éléments important du style fonctionnel est le "pattern-matching" un sorte de décomposition automatique

Dans certains langages, on utilise des listes, et l' opérateur qui ajoute un élément en tête de la liste est ::

On va alors faire le pattern-matching du genre
si tête::queue = maliste ...
traiter la tête
recommencer avec la queue
pour automatiquement séparer la tête de la queue de maliste sans avoir à faire d'indexation ou d'appel de fonction d' extraction d'une sous-liste

Swift est très rugueux encore sur ce point, il n'y a rien pour les tableaux, ou alors c'est encore buggué. Pour les tuples, celà peut fonctionner
let (tête:Int, queue:Int...) = (0, 1, 2, 3)
décompose bien le tuple en tête et queue, ou presque parce que queue devient un Array, ce n'est plus un tuple. Un tuple est une association arbitraire de valeurs, séparées par une virgule entre parenthèses.

Je n'ai pas pu m'attaquer à un exercice "classique" que l'on peut écrire dans n'importe quel langage récursif:
- Imaginez que vous devez payer un certain montant M, et que vous avez des piles de pièces devant vous
- Trouver la formule qui indique combien il y a de manières de combiner les pièces pour payer la somme M, on cherche le nombre de réponses, pas la liste des réponses.

Les cas triviaux:
- Si on n'a aucune pièce, quel que soit le montant à payer, il y a zéro solution
- Si le montant est négatif, il n'y a pas de solution
- Il y une et une seule manière de payer un montant de zéro: ne rien donner, et c'est compté pour une solution valide

Autre cas:
- Quel que soit le montant, si on n'a qu'une pile de 1, il n'y a qu'une solution (n fois la pièce de 1)

C'est de la récursion pure, ça se résoud par la parole avant de le mettre sur papier (ou sur écran):
- Imaginez comment on peut couper en deux parties complémentaires l'ensemble des solutions, le résultat est la somme du nombre de solutions de chaque partie.

L'ordre des piles n'a aucune importance:
- Essayez de bien digérer le raisonnement, très simple : Soit on utilise la première pile, soit on ne l'utilise pas, et ça constitue les deux sous-ensembles recherchés.... toute solution est soit dans l'un soit dans l'autre.

Si on n'utilise jamais la première pile c'est comme si on s'était compliqué la vie en résolvant le problème avec le même montant, mais avec une sélection de pièces plus réduite
Si on utilise la première pièce dans toutes les solutions, que se passe t-il si on l'enlève de chacune de ces solutions, il peut en rester d'autres, des pièces du même type ans la solution ? N'est-ce pas comme si on s'était posé le problème avec les mêmes pièces, mais avec un montant plus réduit (avec la pièce en moins)

Donc...
Je vous laisse gamberger smile.gif ça fonctionne dans n'importe quel langage, y compris en PHP ou en Javascript...

Pour valider
Nombre de solutions pour montant = 3 et piles = (1, 2) = 2
On peut les lister:
1 + 1 + 1
2 + 1

5 et (1, 2) = 3
2 + 2 + 1
2 + 1 + 1 + 1
1 + 1 + 1 + 1 + 1

100 et (1, 5, 10, 25, 50) = 292

Le langage importe peu. C'est une stimulation pour nous inciter à penser de nouveau autrement qu'en assemblage d'objets. Mais si le langage le permet avec facilité, il nous aura aidé à franchir un seuil de complexité de plus.

J-P
Réf : SICP: Structure & Interpretation of Computer Programs: http://mitpress.mit.edu/sicp/full-text/boo....html#%_idx_654
http://rosettacode.org/wiki/Count_the_coins


Ce message a été modifié par Jaypee - 19 Jul 2014, 16:28.
Go to the top of the page
 
+Quote Post
Jaypee
posté 19 Jul 2014, 21:20
Message #11


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 486
Inscrit : 29 Aug 2002
Membre no 3 340



En APL, ça ne dévoile pas grand chose :
Code
MacBookPro-JP:~ jaypee$ apl --noColor
                                      
                    ______ _   __ __  __    ___     ____   __
                   / ____// | / // / / /   /   |   / __ \ / /
                  / / __ /  |/ // / / /   / /| |  / /_/ // /  
                 / /_/ // /|  // /_/ /   / ___ | / ____// /___
                 \____//_/ |_/ \____/   /_/  |_|/_/    /_____/
                                      
                     Welcome to GNU APL version 1.3 / 6056
                                      
                Copyright (C) 2008-2014  Dr. Jürgen Sauermann
                       Banner by FIGlet: www.figlet.org
                                      
                This program comes with ABSOLUTELY NO WARRANTY;
                          for details run: apl --gpl.
                                      
     This program is free software, and you are welcome to redistribute it
         according to the GNU Public License (GPL) version 3 or later.
                                      
[0] ∇ z←M compte Pieces                                    
[1] z←1 ◊ →0×⍳M=0                                        
[2] z←0 ◊ →0×⍳M<0 ◊ →0×⍳0=⍴Pieces                        
[3] z←((M - 1↑,Pieces) compte Pieces) + M compte 1↓,Pieces
[4] ∇

      100 compte 1 5 10 25 50
292

smile.gif et c'est pas sur Rosetta
J-P

Ce message a été modifié par Jaypee - 20 Jul 2014, 08:37.
Go to the top of the page
 
+Quote Post
Jaypee
posté 20 Jul 2014, 08:34
Message #12


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 486
Inscrit : 29 Aug 2002
Membre no 3 340



Bon... Revenons à Swift !

Bien que le pattern-matching ne fonctionne pas bien, on peut quand même utiliser une fonction auxiliaire qui va extraire la tête et la queue d'un tableau et les retourner comme une paire (tête, queue) puisque Swift le permet:
Code
// Décompose un tableau de n'importe quel type T. Array<T> ou [T] sont équivalents.
func décompose<T>(x:[T]) ->(T, [T]) {
    var y = Array<T>()
    for z in x[1..<x.count] {
        y.append(z)
    }
    return (x[0],y)
}
Ce que j'ai appris, avec cet exemple: x[1..<x.count] n'est pas un Array, mais un Slice et on ne peut le retourner tel quel, il faut reconstruire un tableau neuf.

On peut ensuite utiliser le pattern-matching d'une paire de booléens qui vont résumer toutes les situations et et éviter une cascade de if then else, le cas par défaut est obligatoire, noter le "wildcard" _, qui permet d'ignorer le deuxième booléen:
Code
func façonsdDePayerMontantAvecPièces(montant: Int, pièces: [Int]) -> Int {
    switch(montant > 0, pièces.count > 0 ) {
    case (false, _):
        if montant == 0 {
            return 1
        } else {
            return 0
        }
    case (true, false):
        return 0
    default:
        let (p1, reste) = décompose(pièces)
        return façonsdDePayerMontantAvecPièces(montant - p1, pièces) + façonsdDePayerMontantAvecPièces(montant, reste)
    }
De fait, pour les cas simples, ce code fonctionne tès bien dans Playground,
Code
façonsdDePayerMontantAvecPièces(0, [1]) -> 1
façonsdDePayerMontantAvecPièces(0, []) -> 1
façonsdDePayerMontantAvecPièces(-1, [1]) -> 0
façonsdDePayerMontantAvecPièces(2, [1]) -> 1
façonsdDePayerMontantAvecPièces(3, [1, 2]) -> 2
mais pour le cas (100, [1,5,10,25,50]) il mouline à perte de vue, Pas de réponse au bout de 20 minutes. Ce code moins élégant, s'est révélé un peu plus efficace au bout d'une dizaine de minutes quand même. Pour comparaison, l'APL, aussi interprété, répond en quelques secondes.
Code
func façonsdDePayerMontantAvecPièces(montant: Int, pièces: [Int]) -> Int {
    if montant < 0 {
        return 0
    } else if montant == 0 {
        return 1
    } else if pièces == [] {
        return 0
    } else {
       let (première, reste) = décompose(pièces)
       return façonsdDePayerMontantAvecPièces(montant - première, pièces) + façonsdDePayerMontantAvecPièces(montant, reste)
    }
}
En fait, j'ai trouvé une solution pour les Slices... Il ne faut pas tourner le dos à Cocoa et à la richesse de la bibliothèque existante
Code
let x: NSArray = [0, 1, 2, 3, 4] -> [0, 1, 2, 3, 4]
x.count -> 5
let r = NSRange(location:1, length: x.count - 1) -> (1,4)
x.subarrayWithRange -> [1, 2, 3, 4]

Mais comment concilier les types... Voici une solution possible qui se suffit à elle-même, la fonction décompose peut-être oubliée:

Code
func façonsdDePayerMontantAvecPièces(montant: Int, pièces: NSArray) -> Int {
    if montant == 0 {
        return 1
    } else if montant < 0 || pièces == [] {
        return 0
    } else {
        let (première, reste) = (Int(pièces.firstObject as NSNumber), pièces.subarrayWithRange(NSRange(location: 1, length: pièces.count - 1)))
        return façonsdDePayerMontantAvecPièces(montant - première, pièces) + façonsdDePayerMontantAvecPièces(montant, reste)
    }
}
Idéalement, faudrait rendre la récursion terminale...
J-P
PS: Xcode 6 beta 3 est une beta, il crashe souvent après être resté au repos longtemps, il y a probablement une fuite de mémoire quelque part. J'envoie un rapport à chaque crash maintenant.

Ce message a été modifié par Jaypee - 20 Jul 2014, 16:05.
Go to the top of the page
 
+Quote Post
solex46
posté 21 Jul 2014, 13:04
Message #13


Macbidouilleur de bronze !
**

Groupe : Membres
Messages : 457
Inscrit : 18 Jun 2014
Membre no 190 920



Bonjour,

Alors la question c'est :"on tente ?"
C'est vrai que ça a l'air sympathique au niveau syntaxe.

Mais hum...
Pas pour l'instant en fait. cool.gif

1 - Pas mal de bugs trainent encore, vu la jeunesse du langage, y compris dans ses fondations. On verra quand ça sera plus en beta.

2 - Quand je vois déjà comment XCode 5 me bouffe les ressources de mon iMac 2010 core i5 tellement il est lourdaud par rapport à d'anciennes versions que j'utilise toujours régulièrement (sous Snow : Xcode 3) ... je frémis à l'idée d'essayer XCode 6 en beta.
Désolé, mais j'ai pas prévu d'exctincteur dans mon bureau pour éteindre le CPU biggrin.gif

3 - De ce que j'ai lu, ça va être dur de continuer à programmer avec le type de pattern que j'affectionne... à savoir très éloigné de ce que préconise Apple (mais ça marche très bien chez moi, merci).

Ce "pattern" Observable/Observateur me laisse complètement froid, déjà que j'ai jamais pu blairer le MVC... et que j'évite de l'utiliser dès que je peux !
En fait ce que j'apprécie dans la programmation c'est qu'il y a souvent 20000 façons différentes d'écrire la même routine.
Et tout ce qui concoure à me faire programmer "d'une certaine manière" en m'assurant que "c'est mieux" me HÉRISSE.
Pas vous ?
Vous n'êtes pas conformiste à ce point là, quand même ?

4 - et puis c'est malin !
Juste au moment où, au bout de 6 ans, je commençais à vraiment être à l'aise avec Objective-C... et à l'apprécier laugh.gif

Ceci dit, merci pour toutes ces élucubrations, je crois qu'on n'a pas fini d'en entendre parler. smile.gif

(Par contre, j'espère bien qu'Apple ne va pas laisser tomber Objective-C et ses APIs cocoa avant trèèèès longtemps, car ce serait réellement se tirer une balle dans les bu... mad.gif )


--------------------
iMac 27" late 2013 - Mavericks, iMac 27" mid 2010 - Mavericks, iPad mini 1 - iOS 8. Et diverses vieilleries.
Mon site web : ANTIOPA NATURE
Go to the top of the page
 
+Quote Post
Jaypee
posté 21 Jul 2014, 14:47
Message #14


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 486
Inscrit : 29 Aug 2002
Membre no 3 340



Entièrement d'accord. Pour le moment, on vise une cible mouvante...
Si ça ne marche pas, soit on a mis à côté soit ... on est en plein dans le mille, mais ça ne fonctionne pas.

Si le suivi de la bêta est bient fait avec des màj fréquentes ça pourrait aller.
La doc c'est un peu l'appartment-témoin on n'est pas assuré d'avaoir la même chose sur son Mac.

Il y a eu beacoup d'évangélisation par les pionniers (un peu comme je le fais ici) mais je commence à bien sentir ce à quoi m'attendre: Tout n'est pas rose. On est au milieu du guet où ce qui ne marche pas encore peut être bricolé en Cocoa. Mais ça doit être une bidouille temporaire, car sinon le nouveau langage y perdra son âme, un peu comme ce que j'ai décrit pour Java 8: ça peut marcher, mais ça exige un engagement pour l'adopter, il ne gagne pas le respect par son propre mérite.

Dans le monde des développeurs Java, le même problème se pose avec Scala. Nouveau langage, syntaxe ultra-légère, super séduisante, "inter-opérable" avec les libs existantes etc... Mais il oblige à la transition de la POO vers la P. fonctionnelle, et se retrouver dans des chaussettes de débutants rebute les experts de l'ancien langage.

Pour ce qui est du parallélisme et de la facilité de le mettre en oeuvre avec la ProgFonc, je peux citer l'exemple de Clojure (un néo LISP) et de SuperCollider (un synthé musical Open Source) et OverTone est une lib Clojure pour programmer/analyser de la musique en générant les événements temporels, note par note pour lier les deux, et le résultat est écoutable (chercher sur Google les références à Sam Aaron: http://meta-ex.com/ ou à Jeff Rose)

Curieusement (soyons polémiques) Microsoft a déjà pris une longueur d'avance sur ce style fonctionnel, avec LINQ ou F#.

C'est une lame de fond, il sera difficile de surfer à côté sans monter sur cette vague.

J-P
PS: Je suis sur un MacBookPro de milieu 2010 (5.3 je crois, pas encore les Core i3/5/7, un simple core 2 duo) 8 Mo de RAM 1 To de SSHD (hybride SSD/HDD) XCode6b3 est raisonnablement rapide, mais beaucoup de situations le rendent "pensif" et faut l'interrompre

Ce message a été modifié par Jaypee - 21 Jul 2014, 16:12.
Go to the top of the page
 
+Quote Post
Jaypee
posté 27 Jul 2014, 06:54
Message #15


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 486
Inscrit : 29 Aug 2002
Membre no 3 340



J'ai jeté un œil rapide sur la beta4, sortie le 17 juillet.

Pas de progrès sur les deux points qui avaient retenu mon attention :
- Les "Nested functions" ne fonctionnent toujours pas
- Les performances du playground sont toujours aussi faibles, mais ce n'est pas une priorité à ce stade du développement.

J-P
Go to the top of the page
 
+Quote Post
Jaypee
posté 4 Aug 2014, 09:59
Message #16


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 486
Inscrit : 29 Aug 2002
Membre no 3 340



J'ai entendu une définition de la programamtion réactive qui peut peut-être nous éclairer:
Dans le Style fonctionnel, on dit que les fonctions sont des données de première classe. Pensez à la chaîne de caractères, qui est une donnée de première classe, dans tous les langages:
  • On peut l'initialiser
  • On peut l'utiliser sans la nommer: printf("Hello, World")
  • On peut la composer printf("Hello %s", nom)
  • On peut la passer dans une fonction. Il faut pouvoir déclarer le paramètre, comme on passerait fonction(s : string), on peut passer fonction(f:((Int, Int)-> Int))
  • On peut la retourner comme résultat de fonction.
Notamment pour les fonctions, la fonction anonyme ( x -> x * x) (5) donne 25, sans qu'on ait besoin de lui donner un nom, c'est une fonction lambda, anonyme. Note, la lambda est factuellement une fonction anonyme. Certains mélangent les choses et les appelle "closure" ou fermeture mais ce n'est pas exactement la même chose. Dans closure, il y a la notion qu'on fige aussi une partie de l'environnement avec la définition. Par exemple f(x) = (x + y) Quelle valeur de y va-t-on utiliser? Celle qui existait au moment de la définition comme photographiée, ou celle qui peut être définie à tout moment, de manière dynamique? Chaque langage fait son choix d'implémentation et il faut en être conscient.

Dans le style Réactif, les événements sont des données de première classe. (Tomas Petricek, http://tomasp.net)
On peut imaginer des "flots" ("streams") d'événements, que l'on peut filtrer avec un certain prédicat, paralléliser, supprimer du flot. On peut les initialiser, les passer, les ressortir de fonctions etc...

Cela peut être un sujet de méditation pour aujourd'hui smile.gif

J-P

Ce message a été modifié par Jaypee - 4 Aug 2014, 11:57.
Go to the top of the page
 
+Quote Post
Som
posté 7 Aug 2014, 14:16
Message #17


Macbidouilleur de bronze !
**

Groupe : Membres
Messages : 266
Inscrit : 5 Jan 2013
Lieu : New York
Membre no 181 722



Swift est dela pure cochonnerie.
On dirait qu'il y'a eu du monde de Microsoft qui ont aboutit là et apportent leur influence (mauvaise influence).
Ça déjà commencé dans Objective-C avec l'introduction de quelques tri importé de vb/c# comme les propriétés (Getter/Setter) un très mot design.
Question design on en rajoute avec les variables que l'on peut nommer avec n'importe quel symbole y compris des émoticons. Le code sera facile à lire et maintenir comme ça surtout dan les projet énormes. Ça va vraiment aider à développer des bonnes pratiques.


Plus haut on lit n'importe quoi. Pour les fonction, on peut les passer en paramètre et les retourner, en C , il suffit d'utiliser des pointeurs et des typedef.
On a déjà introduit des fonctions anonymes et les les Blocks dans Objective C et dans C/C++ /xCode et sous c'est standardisé dans C++ 11.
Question design pattern, je ne vois rien que plus de confusion. Ceux qui y accordent de l'importance savent comme dealer avec ça, peu importe le langage OO.

Tout ce que je vois avec ce "langage" c'est une tentative de faciliter le move pour les "vb faiseux". C'est programmeurs vb6 qui pondent des cochonneries et des applications incroyablement mal faites/conçues. Quand MS a introduit .net, la laideur envahit en plus le code. Je vois autour de moi (au tavail) du monde nommer des classes avec des verbes, nommer des méthode avec des noms et écrire des des classe de 3500 ligne et plus.

C'est ça ce que apple veut introduire en disant faciliter la programmation pour les nouveau programmeur.
Les nouveau décideurs chez pole suivent la voie de la facilité et de la médiocrité pour on ne sait quelle raison. Probablement pour avoir une plus grande base de développeurs mais la quantité n'a jamais fait le poids par rapport à la qualité.

Pour les milliers de monde qui se ont appris Objective-C on dit quoi ?


Go to the top of the page
 
+Quote Post
Jaypee
posté 19 Aug 2014, 08:42
Message #18


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 486
Inscrit : 29 Aug 2002
Membre no 3 340



Som,

Je trouve ta réaction très violente pour pas grand chose... J'ai beaucoup d'heures de vol en programmation, j'ai utilisé des dizaines d'environnements pour mon activité professionnelle et je peux t'assurer que tous les meilleurs outils de programmation ont leur apogée et leur déclin, rien n'est parfait. Pour ce qui est des programmeurs qui ont investi dans Objective-C, le pari est qu'ils sauront sortir du petit confort dans lequel ils se sont installés pour redécouvrir un nouvel outil, puis pour dépasser rapidement les possibilités de l'ancien.

Il y a des moyens et des besoins nouveaux : Comment consolider l'écosystème Apple pour permettre une homogénéité côté client comme côté serveur. Comment utiliser les Processeurs à coeurs multiples ? Comment réagir à une montée en puissance ? Comment mettre en ligne automatiquement des serveurs supplémentaires, etc... Aussi "beau"que soit Objective-C, il n'a aucune réponse à ça, et les superbes applis iPhone dépendent probablement d'un serveur, peut-être sous Windows, peut-être écrit en C#... L'ambition d'Apple avec Swift telle que je la lis entre les lignes, c'est ça : Plus d'Apple côté serveur, donc une probable ouverture à l'Open Source, peut-être de nouveau serveurs,...

Swift est à la fois "réactif" et "fonctionnel"... Il n'existe que des bêtes de labo dans cette catégorie, et c'est typiquement "Apple" de faire un pari sur une technologie nouvelle : Ils se sont plantés souvent, mais ils ont souvent fait preuve de courage en tournant le dos au passé, et le temps leur a donné raison.

La seule chose qui ne changera pas, c'est la constance du changement, ce qui est , ne sera plus...

J-P

Ce message a été modifié par Jaypee - 19 Aug 2014, 11:58.
Go to the top of the page
 
+Quote Post
Jaypee
posté 20 Aug 2014, 12:34
Message #19


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 486
Inscrit : 29 Aug 2002
Membre no 3 340



J'ai continué un peu les essais avec la Bêta 6

Les performances de Playground sont sensiblement meilleures. Cependant, ayant changé de Mac pour un mini Core i7, je ne peux pas faire la part de l'amélioration soft ou de l'amélioration hard.
Les fonctions "nested" n'ont pas changé, j'espère qu'elles ne resteront pas dans cet état, car ce serait très dommageable si ces fonctions ne peuvent s'appeler entre elles, ou si elle ne peux être récursives.

J-P

Ce message a été modifié par Jaypee - 20 Aug 2014, 12:35.
Go to the top of the page
 
+Quote Post
Jaypee
posté 31 Aug 2014, 09:10
Message #20


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 486
Inscrit : 29 Aug 2002
Membre no 3 340



J'ai trouvé un style un peu meilleur pour mon code sur le comptage des façons de payer...
Code
import Cocoa


func façonsdDePayerMontantAvecPièces(montant: Int, pièces: [Int]) -> Int {
    if montant == 0 {
        return 1
    } else if montant < 0 || pièces == [] {
        return 0
    } else {
        var toutSaufDernière = pièces
        let dernière = toutSaufDernière.removeLast()
        return façonsdDePayerMontantAvecPièces(montant - dernière, pièces) + façonsdDePayerMontantAvecPièces(montant, toutSaufDernière)
    }
}

façonsdDePayerMontantAvecPièces(100, [1, 5,  10, 25, 50])

Les langages qui privilégient les listes, ont leurs primitives pour raisonner sur la tête et la queue. Swift privilégie les tableaux, et raisonne plus facilement sur le dernier élément.
Il y a un truc cependant. Les tableaux passés par valeur aux fonctions sont immuables, et la primitive qui enlève le dernier élément, n'opère que sur un tableau mutable
Donc, il faut d'abord faire une copie mutable.
Pourquoi ne pas utiliser pièces.last ? Parce qu'elle retourne un Int? Dans d'autres langages on dirait : Some(Int) ou Option[Int] ou Optional.of(Integer), c'est à dire un résultat qui pourrait être vide.
Alors que curieusement tableau.removeLast() retourne la valeur supprimée, et réduit de taille le tableau

à suivre, la bêta 7 devrait sortir demain.
J-P
PS: Sur Twitter les hashtags #swift et #swiftlang montrent l'ampleur de l'engouement, et on y retrouve les ténors d'Objective-C qui ont effectivement l'esprit large smile.gif
Il y a même des benchmarks ( chercher Apples-to-Apples ) et Swift compilé se révèle très performant, parfois même plus performant qu'Objective-C.

Go to the top of the page
 
+Quote Post
Jaypee
posté 31 Aug 2014, 09:31
Message #21


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 486
Inscrit : 29 Aug 2002
Membre no 3 340



Sur un blog, j'ai vu la résolution d'un de ces problèmes classiques et celui-ci vient du guide "Apprendre Haskell vous fera le plus grand bien", un tutoriel en ligne pour le langage Haskell

Le problème est celui du parcours de Heathrow à Big-Ben, qui consiste à trouver un chemin de moindre coût dans un graphe valué, un genre de minimax: Le problème expliqué en Français

Code sur GitHub

Un problème similaire (on génère des chemins) est celui des pots : Un robinet, un évier, n pots, de capacité {C(1)..C(n)}, mais contenant effectivement un certain niveau d'eau < capacité.
Problème : comment obtenir une quantité V, d'eau en combinant les opérations possibles : remplir un pot au robinet, le vider dans l'évier, verser le pot x dans le pot y, soit jusqu'à vider x, soit jusqu'à remplir y.

J-P

Ce message a été modifié par Jaypee - 31 Aug 2014, 09:42.
Go to the top of the page
 
+Quote Post
Jaypee
posté 31 Aug 2014, 17:13
Message #22


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 486
Inscrit : 29 Aug 2002
Membre no 3 340



Encore un peu plus minimaliste :
- Le tableau est passé comme var, il est donc mutable
- On prend une copie immuable avant la transformation
- pièces.removeLast() et pièces représentent la dernière valeur et les pièces avec une pile en moins.
Code
import Cocoa

func façonsdDePayerMontantAvecPièces(montant: Int, var pièces: [Int]) -> Int {
    if montant == 0 {
        return 1
    } else if montant < 0 || pièces == [] {
        return 0
    } else {
        let piècesAvant = pièces
        return façonsdDePayerMontantAvecPièces(montant - pièces.removeLast(), piècesAvant) + façonsdDePayerMontantAvecPièces(montant, pièces)
    }
}

façonsdDePayerMontantAvecPièces(100, [1, 5,  10, 25, 50])


Résultat attendu = 292

J-P
Go to the top of the page
 
+Quote Post
Jaypee
posté 31 Aug 2014, 19:00
Message #23


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 486
Inscrit : 29 Aug 2002
Membre no 3 340



En fait Swift reste très proche du style Objective-C avec ses noms segmentés, exemple de constructeur
Code
class Personne {
    var prénom: String
    var nom: String
    init(avecPrénom prénom: String, etNom nom: String) {
        self.prénom = prénom
        self.nom = nom
    }
}

let moi = Personne (avecPrénom: "Jean-Pierre", etNom: "Mon nom")


JP

Ce message a été modifié par Jaypee - 31 Aug 2014, 19:01.
Go to the top of the page
 
+Quote Post
Jaypee
posté 3 Sep 2014, 08:10
Message #24


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 486
Inscrit : 29 Aug 2002
Membre no 3 340



Xcode 6 Beta 7 est dispo au téléchargement
Xcode 6 GM est dispo au téléchargement
Xcode 6.1 beta 2 Yosemite est dispo au téléchargement

Ce message a été modifié par Jaypee - 16 Sep 2014, 06:23.
Go to the top of the page
 
+Quote Post
Jaypee
posté 17 Sep 2014, 11:28
Message #25


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 486
Inscrit : 29 Aug 2002
Membre no 3 340



Un exemple perso que je crois intéressant de partager...
C'est un début de résolution du problème des pots ou des verres:
- Ils ont une certaine capacité chacun
- 3 actions sont possibles : remplir / vider / verser de l'un vers l'autre
Problème comment obtenir une certaine quantité : Dans cet exemple on part avec 3 verres de capacité 3, 5, 9
Comment obtenir 7?
Tous les verres sont vides
On remplit 5
On verse 5 dans 3, il reste 2 au fond
On vide 3, on verse 2 dedans
On remplit 5
On verse 2 dans 9
On verse 5 dans 9
Il manque l'intelligence artificielle pour générer ce plan, mais voici la structure qui va permettre de la créer

CODE
import Foundation

typealias Niveau = [Int]

protocol ChangeurNiveau {
func change(niveau: Niveau) -> Niveau
}

let Capacité = [3, 5, 9]

// niveauInitial de même dimension que Capacité, mais rempli de zéros
var niveauInitial = Capacité
niveauInitial = niveauInitial.map({x in x * 0})

// Chaque action change le niveau
enum Action: ChangeurNiveau {

case Vider(Int)
case Remplir(Int)
case Verser(Int, Int)

// Implémenter le protocole ChangeurNiveau
func change(niveau: Niveau) -> Niveau {
var résultat = niveau
switch self {
case .Vider(let verre):
résultat[verre] = 0
return résultat
case .Remplir(let verre):
résultat[verre] = Capacité[verre]
return résultat
case let .Verser(depuis, vers):
let qtéVersable = niveau[depuis]
let qtéRemplissable = Capacité[vers] - niveau[vers]
if qtéVersable >= qtéRemplissable {
résultat[depuis] = qtéVersable - qtéRemplissable
résultat[vers] = Capacité[vers]
} else {
résultat[depuis] = 0
résultat[vers] += qtéVersable
}
return résultat
default:
return résultat
}
}
}

// Opérateur
infix operator ~~ { associativity right precedence 160 }

func ~~ (a:Action, n:Niveau) -> Niveau {
return a.change(n)
}
// Copie "invariable" des niveaux
let niveauDépart = niveauInitial

// Recette pour faire 7 avec les capacités [3, 5, 9] et [0, 0, 0] comme niveau initial
Action.Verser(1, 2) ~~ Action.Verser(0, 2) ~~ Action.Remplir(1) ~~ Action.Verser(1, 0) ~~ Action.Vider(0) ~~ Action.Verser(1, 0) ~~ Action.Remplir(1) ~~ niveauDépart
// En programmation fonctionnelle, il existe une fonction sur les Collections appelée fold-right ou foldr qui fait exactement cette accumulation d'application d'opération
// Par exemple [1, 2, 3, 4, 5].foldr(1, *) calcule une factorielle.


var recettePourFaireSept = [Action.Remplir(1),Action.Verser(1, 0),Action.Vider(0),Action.Verser(1, 0),Action.Remplir(1),Action.Verser(0, 2),Action.Verser(1, 2)]

// Source: http://tetontech.wordpress.com/2014/06/08/...al-programming/
extension Array {
func foldr<U>(initial:U, combine:(T,U) -> U) -> U {
if self.count > 0 {
var combined = initial
for element in self{
combined = combine(element,combined)
}
return combined
}
return initial
}
}
// Et donc le résultat recherché peut maintenant s'écrire
var niveauArrivée = recettePourFaireSept.foldr(niveauDépart, ~~)

// Comment vérifier que niveauArrivée contient bien 7
let BUT = 7
let départ = false
// On applique l'opérateur OU partout, avec foldr
let résultat = niveauArrivée.map({x in x == BUT}).foldr(départ, |)
// Le map donne [false, false, true]
// Le foldr fait: false | false | true | départ
// Il suffit d'un seul Vrai pour rendre Vrai toute la suite de "OU"
println(résultat)
println([1, 2, 3, 4, 5].foldr(1,*))


Pour créer l'IA, il faut maintenant:
- énumérer toutes les actions possibles: il y en a douze pour 3 verres: Remplir(n), Vider(n) => 6, Verser(n, m) avec n différent de m: 3 x 3 => 9 - {0,0 1,1 - 2,2} => +6 = 12
- Puis générer toutes les stratégies possibles à 1 action, 2 actions, 3 actions etc... avec une seule restriction ne pas se répéter tout de suite:
12 choix pour la première action
11 choix pour la seconde
11 choix pour la 3ème...

- Filtrer l'ensemble des stratégies possibles par le prédicat: contient le BUT.

Cela va me conduire à examiner les "lazy Collections", qui permettent de définir des Collections infinies, comme la Collection de tous les Entiers positifs.

J-P

Ce message a été modifié par Jaypee - 18 Sep 2014, 05:52.
Go to the top of the page
 
+Quote Post
Jaypee
posté 21 Sep 2014, 12:01
Message #26


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 486
Inscrit : 29 Aug 2002
Membre no 3 340



J'ai un code complet avec l'IA, mais pas parfait.
Je n'ai pas trouvé encore comment utiliser les "lazy collections". L'idée est qu'elles ne consomment pas de mémoire, elles mémorisent la recette pour les fabriquer, et seulement lorsqu'un vrai calcul est demandé, le sous-ensemble utile de la collection est créé en mémoire.
Par ailleurs, comme je publie aussi ailleurs ce genre de d'expérimentation, j'ai tout écrit en anglais. Désolé pour ça.

Parlons des difficultés rencontrées : la principale difficulté a été d'explorer les solutions en largeur d'abord. Ce que je faisais sans m'en rendre compte était de m'enfoncer dans une branche pour chercher une solution "plus bas" au lieu de chercher à côté, en explorant un nouveau fils, petit-fils, arrière-petit-fils, avant d'examiner tous les neveux.

Au final, il m'a produit 3+ solutions auxquelles je n'avais pas pensé smile.gif
Code
MacMiniJP:Desktop jaypee$ time xcrun swift pouring.swift # On part de 3 verres vides numérotés 0, 1 et 2, de 3, 5, 9 de capacité, et on veut obtenir 7. Fill = Remplir, Pour = Verser
MacMiniJP:Desktop jaypee$ time xcrun swift pouring.swift
<<<**** Solution **********
[
  Fill(0)
  Fill(2)
  Pour(0, 1)
  Pour(2, 1)
]
************************>>>
<<<**** Solution **********
[
  Fill(0)
  Fill(2)
  Pour(2, 1)
  Pour(0, 2)
]
************************>>>
<<<**** Solution **********
[
  Fill(0)
  Pour(0, 1)
  Fill(2)
  Pour(2, 1)
]
************************>>>
<<<**** Solution **********
[
  Fill(2)
  Fill(0)
  Pour(0, 1)
  Pour(2, 1)
]
************************>>>
<<<**** Solution **********
[
  Fill(2)
  Fill(0)
  Pour(2, 1)
  Pour(0, 2)
]
************************>>>
<<<**** Solution **********
[
  Fill(2)
  Pour(2, 1)
  Fill(0)
  Pour(0, 2)
]
************************>>>
....

Les verres étant vides, j'ai fait 3 hypothèses de première action: remplir tour à tour chacun des verres.
CODE
import Foundation

extension Array {
func foldr<U>(initial: U, combine: (T,U)-> U) -> U {
if self.count > 0 {
var combined = initial
for element in self {
combined = combine(element, combined)
}
return combined
}
return initial
}
}

typealias State = [Int]

protocol StateMutator {
func change(state: State) -> State
}

protocol TextRepresentable {
func asText() -> String
}

let capacity = [3, 5, 9]
var initialState = capacity
initialState = initialState.map({x in x * 0})

enum Move: StateMutator, TextRepresentable, Equatable {

case Empty(Int)
case Fill(Int)
case Pour(Int, Int)

func change(state: State) -> State {
var newState = state
switch self {
case .Empty(let glass):
newState[glass] = 0
return newState
case .Fill(let glass):
newState[glass] = capacity[glass]
return newState
case let .Pour(from, to):
let src = state[from]
let dest = capacity[to] - state[to]
if src >= dest {
newState[from] = src - dest
newState[to] = capacity[to]
} else {
newState[from] = 0
newState[to] += src
}
return newState
default:
return newState
}
}

func asText() -> String {
switch self {
case .Empty(let glass): return "Empty(\(glass))"
case .Fill(let glass): return "Fill(\(glass))"
case let .Pour(from, to): return "Pour(\(from), \(to))"
}
}

}


infix operator ~~ {
associativity right
precedence 160
}

func ~~ (left: Move, right: State) -> State {
return left.change(right)
}

func == (left: Move, right: Move) -> Bool {
return left.asText() == right.asText()
}

func != (left: Move, right: Move) -> Bool {
return !(right == left)
}

let LIMIT = initialState.count
let glasses = 0..<LIMIT
// All possible moves
typealias Path = [Move]

var moves = [Move]()
for g in glasses {
moves.append(Move.Empty(g))
}
for g in glasses {
moves.append(Move.Fill(g))
}
for g in glasses {
for h in filter(glasses, {x in x != g}) {
moves.append(Move.Pour(g,h))
}
}

func showPath(path: Path) {
println("[")
path.map({ x in println(" \(x.asText())")})
println("]")
}

class PathBuilder {
func extend(from: [Path]) -> [Path] {
var result = [Path]()
for fromPath in from {
let lastMove = fromPath.last
if lastMove == nil {
result = [[Move.Fill(0)], [Move.Fill(1)], [Move.Fill(2)]]
} else {
for move in filter(moves, {x in x != lastMove!}) {
var path = fromPath
path.append(move)
result.append(path)
}
}
}
return result
}
func containsTarget(path: Path, target: Int) -> Bool {
return (path.foldr(initialState, ~~).map({x in x == target})).foldr(false,|)
}
}

func evaluate(start: Path, target: Int, pathBuilder: PathBuilder) -> Bool {
if pathBuilder.containsTarget(start, target: target) {
println("<<<**** Solution **********")
showPath(start)
println("************************>>>")
return true
}
return false
}

func resolve(var starts: [Path], target: Int) {
var pathBuilder = PathBuilder()
starts.filter({x in !evaluate(x, target, pathBuilder)})
var nextSteps = pathBuilder.extend(starts)
resolve(nextSteps, target)
}
resolve([[]], 7)


J'ai lu un problème similaire sur Quora: Avec un sablier de 5 mn et un autre de 7mn, comment mesurer 6 minutes.
J-P
PS: J'ai légèrement changé le code pour qu'il se débrouille sans aide. en partant de rien: [[]] et la recherche est plus complète, encore plus de solutions nouvelles

Ce message a été modifié par Jaypee - 24 Sep 2014, 06:17.
Go to the top of the page
 
+Quote Post
Jaypee
posté 30 Oct 2014, 07:10
Message #27


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 486
Inscrit : 29 Aug 2002
Membre no 3 340



Une excellente présentation (en Anglais) sur la programmation fonctionnelle en Swift, et la comparaison avec Objective-C. C'est à la base le même code, mais c'est le style qui fait la différence :

Video + Slides + code sur le site.

J-P

Ce message a été modifié par Jaypee - 30 Oct 2014, 07:14.
Go to the top of the page
 
+Quote Post
No6
posté 30 Oct 2014, 13:07
Message #28


Oui ?
*****

Groupe : Membres
Messages : 3 889
Inscrit : 24 Jun 2003
Lieu : BZH
Membre no 8 224



On peut écrire du code très propre et minimaliste en coffeeScript.

Je crois même qu'on peut en passer en mode "partern" ?

sous nodeJs on à "système' beaucoup plus abouti et qui à l'avantage de fonctionner aussi bien dans l'univers Apple (Mac OS et IOS) que dans celui d'androïd et Windows...

Alors pourquoi se prendre la têtes avec Swift ??? blink.gif

Ce message a été modifié par No6 - 30 Oct 2014, 13:26.


--------------------
"Je sais que vous croyez comprendre ce que vous pensez que j'ai dit, mais je ne suis pas sûr que vous réalisiez que ce que vous avez entendu n'est pas ce que je pense."
(Alan Greenspan)
Go to the top of the page
 
+Quote Post
Jaypee
posté 31 Oct 2014, 22:56
Message #29


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 486
Inscrit : 29 Aug 2002
Membre no 3 340



Pour le moment, je me contente d'explorer Swift, pour évaluer sa flexibilité, sans même me préoccuper de la présentation. Et jusqu'à présent, je n'ai rien trouvé d'embêtant.
L'exemple que j'ai utilisé est un classique de l'Intelligence Artificielle.

Il fut un temps où pour toucher à tel ou tel domaine, il fallait tel ou tel langage, et les autres devaient s'en passer.
Il existe de très bonnes applications sous Android qui n' existent pas sous iOS ou Windows Mobile, et c'est vrai aussi pour chacun des autres OS.
La portabilité n'est pas une fin en soi, c'est juste une contrainte industrielle.

Ce qui est important, à mon avis, c'est de pouvoir matérialiser une idée innovante. Si elle implique de traiter des Data, il faut pouvoir le faire, s'il faut un moteur physique, de même, ou de l'intelligence artificielle. Voilà ce que jusqu'à présent j'ai trouvé avec Swift. Un nouveau vélo pour l'esprit, comme dirait Jobs.

On ne se prend pas la tête, sauf qu'en face d'un problème dont il faut inventer la solution, mieux vaut avoir les coudées franches et prendre le risque de bien s'amuser en le faisant.
Je viens de passer ma journée avec du beau code web bien industriel, à le protéger contre 11 attaques de hackers différentes... C'est bien, mais ça me suffit largement. Rentré chez moi, si je dois m'intéresser à du code, j'aime autant zapper, passer à autre chose.

Voilà "pourquoi", je ne "me prends pas la tête" avec Swift, au contraire, je me nettoie les neurones...
J-P
Go to the top of the page
 
+Quote Post
Jaypee
posté 2 Nov 2014, 09:49
Message #30


Macbidouilleur d'Or !
*****

Groupe : Membres
Messages : 2 486
Inscrit : 29 Aug 2002
Membre no 3 340



Pour conclure cette série, j'ai tout repris et simplifié le code et surtout, j'en ai fait un livre comme l'exemple des Balloons, en utilisant Markdown et un outil en node.js qui transforme le markdown en playground.

Je souhaite réellement qu'il puisse allumer une étincelle d'intérêt dans l'esprit des éventuels lecteurs.

Il faut cependant reconnaître que les performances de Playground sont à pleurer, j'ai donc aussi joint le code tout seul à compiler et tourner dans un terminal
Si vous ouvrez dans Xcode, il faut laisser le ballon tourner, au bout de quelque minutes, le code s'arrête.

Pour voir la sortie Console, il faut afficher l' Assistant Editor, à droite.
Code
Solution: [Remplir(0), Remplir(2), Verser(0, 1), Verser(2, 1)] -> [0, 5, 7]
Solution: [Remplir(0), Remplir(2), Verser(2, 1), Verser(0, 2)] -> [0, 5, 7]
Solution: [Remplir(0), Verser(0, 1), Remplir(2), Verser(2, 1)] -> [0, 5, 7]
Solution: [Remplir(2), Remplir(0), Verser(0, 1), Verser(2, 1)] -> [0, 5, 7]
Solution: [Remplir(2), Remplir(0), Verser(2, 1), Verser(0, 2)] -> [0, 5, 7]
Solution: [Remplir(2), Verser(2, 1), Remplir(0), Verser(0, 2)] -> [0, 5, 7]
Solution: [Remplir(2), Verser(2, 1), Verser(1, 0), Verser(0, 2)] -> [0, 2, 7]

Voilà, ce sera tout, à part quelques piqûres de rappel si je vois passer une publicaction intéressante sur le sujet.

J-P

Ce message a été modifié par Jaypee - 3 Nov 2014, 07:06.
Fichier(s) joint(s)
Fichier joint  Transvasement.zip ( 24.8 Ko ) Nombre de téléchargements : 1
 
Go to the top of the page
 
+Quote Post

2 Pages V   1 2 >
Reply to this topicStart new topic
1 utilisateur(s) sur ce sujet (1 invité(s) et 0 utilisateur(s) anonyme(s))
0 membre(s) :

 



Nous sommes le : 18th April 2024 - 12:48