[Swift] On tente ?, L'histoire se répète... |
Bienvenue invité ( Connexion | Inscription )
[Swift] On tente ?, L'histoire se répète... |
14 Dec 2014, 10:31
Message
#31
|
|
Macbidouilleur d'Or ! Groupe : Membres Messages : 2 486 Inscrit : 29 Aug 2002 Membre no 3 340 |
La communauté Swift se rebiffe avec ces deux événements qui me paraissent significatifs:
- Le dernier billet du blog officiel présente une solution à un problème de fond: comment un compilateur accède à une méthode. Mais c'est une solution très vieille école, avec beaucoup de recopie de code obligé (boilerplate code) qui est présentée comme la seule bonne solution. Ses inconvénients et défauts ne sont même pas détaillés. - Les performances de Swift compilé, qu'on imagine élevées comme son nom et son ADN le suggèrent, sont en réalité à pleurer. Je l'ai déjà constaté dans Xcode, le REPL Scala basé sur Eclipse et Java est beaucoup plus réactif. Pour vous dire, ses performances sont pires que celles de Ruby qui porte la réputation de n'être pas vif. Un des bugs connus concerne les fonctions privées récursives, une fonctionnalité banale. Il a été marqué résolu, non parce que ces fonctions peuvent être récursives, mais parce qu'au lieu de cracher, le compilateur signale qu'il ne sait pas faire. Et le débat est clos. La communauté a montré comment on contourne le problème par du code obligé: définition vide, suivie d'une modification. Le code obligé, même si c'est pas beau, le compilateur pourrait le générer. Ou le langage devrait supporter des macros... Ce que Swift ne fait pas. Je sens aussi une équipe de développement pas trop cool, en mode défensif. Face à des bugs connus et visibles, il faut réouvrir le design et s'attaquer frontalement au problème, au lieu de défendre l'acquis avec de la propagande. Leur méthodologie de développement ne me semble pas super-agile. Et là, il y a risque, cela peut tuer un bon produit et Apple en a tué bien d'autres, et a peut-être déjà mis Swift dans un siège éjectable, par la faute d'un manager frileux... Qu'au moins ils rendent le langage Open Source, et la communauté se chargera de faire le boulot ingrat et bien plus... J-P Ce message a été modifié par Jaypee - 14 Dec 2014, 10:31. |
|
|
14 Dec 2014, 16:13
Message
#32
|
|
Terminaltor Moderating Machine Groupe : Admin Messages : 24 449 Inscrit : 25 Oct 2002 Lieu : Jeumont (59) Membre no 4 319 |
Au vu de l’évolution d’Objective-C, c’était malheureusement assez prévisible
-------------------- I think therefore I Mac
|
|
|
29 Jan 2015, 07:12
Message
#33
|
|
Macbidouilleur d'Or ! Groupe : Membres Messages : 2 486 Inscrit : 29 Aug 2002 Membre no 3 340 |
Paul Hegarty qui présentait le dev iOS sur iTunes à Stanford, présente maintenant le cours CS193P en Swift
https://itunes.apple.com/fr/course/developi...ift/id961180099 J-P Ce message a été modifié par Jaypee - 5 Feb 2015, 07:06. |
|
|
5 Feb 2015, 07:07
Message
#34
|
|
Macbidouilleur d'Or ! Groupe : Membres Messages : 2 486 Inscrit : 29 Aug 2002 Membre no 3 340 |
Autre université, anglaise cette fois-ci, autre cours : https://itunes.apple.com/fr/course/ios-deve...ift/id950659946
J-P |
|
|
8 Jun 2015, 21:29
Message
#35
|
|
Terminaltor Moderating Machine Groupe : Admin Messages : 24 449 Inscrit : 25 Oct 2002 Lieu : Jeumont (59) Membre no 4 319 |
Et là, il y a risque, cela peut tuer un bon produit et Apple en a tué bien d'autres, et a peut-être déjà mis Swift dans un siège éjectable, par la faute d'un manager frileux... Qu'au moins ils rendent le langage Open Source, et la communauté se chargera de faire le boulot ingrat et bien plus... J-P Steve Jobs t’a entendu du paradis -------------------- I think therefore I Mac
|
|
|
10 Jun 2015, 19:46
Message
#36
|
|
Macbidouilleur d'Or ! Groupe : Membres Messages : 2 486 Inscrit : 29 Aug 2002 Membre no 3 340 |
La version 2.0 a vraiment fait le ménage dans les coins, cette syntaxe simple et naturelle est ENFIN supportée (fonction enchâssée récursive):
Code func factorial(n: Int) -> Int {
func fact(n: Int, accu: Int) -> Int { switch n { case 0: return accu default: return fact(n - 1, accu: n * accu) } } return fact(n, accu: 1) } factorial(5) 120 |
|
|
13 May 2016, 12:44
Message
#37
|
|
Terminaltor Moderating Machine Groupe : Admin Messages : 24 449 Inscrit : 25 Oct 2002 Lieu : Jeumont (59) Membre no 4 319 |
Voilà, le langage me semble suffisamment abouti maintenant pour investir dedans
J’ai pris quelques jours pour me farcir le manuel de 600 pages, il y a beaucoup de trucs bien : * Les types optionnels avec les myriades d’applications ; * Les closures et tout le sucre syntaxique autour ; * Les types tuple, array et dictionary intégrés ; * L’ARC, AMHA bien meilleur que tous les garbage collectors qu’on retrouve maintenant partout (Java, C#, Go, Haskell etc.) ; * Support natif de l’unicode, à la fois dans les chaînes de caractères et dans les noms de variables ; * Les casts dynamiques as / is ; * La gestion d’erreurs ; * Le système de templates (generics) ; * Les protocoles et extensions issus de l’Obj-C ; * Les méthodes statiques de classe héritables ; * Les switch améliorés ; * La possibilité d’intégrer facilement des variables ou calculs au sein d’un chaîne de caractères ; * Les nombreux check automatiques (overflow, subscripts etc.), en espérant qu’ils ne ralentissent pas trop le langage ^^ J’aime moins : * La notation des subscripts multiples [i, j] ; * La nécessité d’avoir des espaces devant != et autour de ?: pour les différencier des opérateurs pré-fixés et post-fixés ? et ! ; * La méthode peu naturelle pour faire une boucle décrémentale. En tout cas, je m’amuse à faire des one-liners sur certains puzzles de CodinGame ^^ Code print((0..<Int(readLine()!)!).map { _ in readLine()! }.sort(<)[0])
-------------------- I think therefore I Mac
|
|
|
30 May 2016, 09:38
Message
#38
|
|
Macbidouilleur d'Or ! Groupe : Membres Messages : 4 969 Inscrit : 26 Jan 2011 Lieu : Pollachius virens Membre no 164 083 |
Quelques articles techniques sur swift par l'équipe des développeurs de little snitch https://blog.obdev.at/tag/swift/
Ce message a été modifié par yponomeute - 30 May 2016, 09:39. -------------------- MBP 2017 15" avec clavier pourri et touchbar inutile
|
|
|
30 May 2016, 14:53
Message
#39
|
|
Terminaltor Moderating Machine Groupe : Admin Messages : 24 449 Inscrit : 25 Oct 2002 Lieu : Jeumont (59) Membre no 4 319 |
Quelques articles techniques sur swift par l'équipe des développeurs de little snitch https://blog.obdev.at/tag/swift/ Ça me semble très orienté réseau ; pas mon truc Sinon, avec "import Glibc", on a accès à pas mal de fonctions des bibliothèques standard ; par exemple j’ai testé "gettimeofday" : Code import Glibc
var time:timeval = timeval() gettimeofday(&time, nil) print(time.tv_sec*1000+time.tv_usec/1000) -------------------- I think therefore I Mac
|
|
|
31 May 2016, 06:19
Message
#40
|
|
Macbidouilleur d'Or ! Groupe : Membres Messages : 2 486 Inscrit : 29 Aug 2002 Membre no 3 340 |
Schlum,
Tu n'as pas cité le "pattern matching" qui évite des if then else compliqués. ou alors permet des affectations en parallèle: let (x, y) = (2.0, 6.5) Du point de vue du langage, le seul cas tordu que je n'avais pas réussi à résoudre porte sur des types de données co-récursifs type A contient un B et type B contient un A. Le cas s'était présenté lorsque j'avais essayé de résoudre le problème "de Heathrow à Londres", un classique du langage Haskell, qui est en gros un parcours dans un graphe (c 'est la 2e partie de http://learnyouahaskell.com/functionally-solving-problems ) Mais je me réjouis de l'attention enfin accordée à ce langage très flexible. @+ JP Ce message a été modifié par Jaypee - 31 May 2016, 06:20. |
|
|
31 May 2016, 09:01
Message
#41
|
|
Macbidouilleur d'Or ! Groupe : Membres Messages : 4 969 Inscrit : 26 Jan 2011 Lieu : Pollachius virens Membre no 164 083 |
Swift coté serveur https://developer.ibm.com/swift/products/ibm-swift-sandbox/
-------------------- MBP 2017 15" avec clavier pourri et touchbar inutile
|
|
|
31 May 2016, 09:11
Message
#42
|
|
Terminaltor Moderating Machine Groupe : Admin Messages : 24 449 Inscrit : 25 Oct 2002 Lieu : Jeumont (59) Membre no 4 319 |
Schlum, Tu n'as pas cité le "pattern matching" qui évite des if then else compliqués. ou alors permet des affectations en parallèle: let (x, y) = (2.0, 6.5) C’est ce que j’entendais par « switch améliorés » Pour les affectations en parallèle, je ne vois pas trop l’intérêt, let x=2.0, y=6.5 est tout aussi court et plus compréhensible. Du point de vue du langage, le seul cas tordu que je n'avais pas réussi à résoudre porte sur des types de données co-récursifs type A contient un B et type B contient un A. Le cas s'était présenté lorsque j'avais essayé de résoudre le problème "de Heathrow à Londres", un classique du langage Haskell, qui est en gros un parcours dans un graphe (c 'est la 2e partie de http://learnyouahaskell.com/functionally-solving-problems ) Ce Heathrow à Londres, c’est un cas simplifié de l’algorithme de Dijkstra, non ? Citation Mais je me réjouis de l'attention enfin accordée à ce langage très flexible. @+ JP Il y a encore des trucs qui ne fonctionnent pas super bien. Par exemple, sur CodinGame il y a un Code Golf où il faut trouver la température la plus proche de 0 dans une liste, en privilégiant la positive en cas de distance égale ; ce qui pourrait s’exprimer comme : Code print(readLine()!.characters.split(" ").map{Int(String($0))!}.sort(>).sort{abs($0)<abs($1)}[0]) Cependant, on reçoit un « error: expression was too complex to be solved in reasonable time; consider breaking up the expression into distinct sub-expressions » Du coup, obligé de splitter : Code let l = readLine()!.characters.split(" ").map{Int(String($0))!}.sort(>) print(l.sort{abs($0)<abs($1)}[0]) Dommage Dommage aussi que String se soit vu retirer sa conformation à CollectionView, ce qui permettait d’écrire directement : Code readLine()!.split(" ").map{Int($0)!} Il y a bien dans Foundation un "componentsSeparatedByString", mais c’est long à écrire, et demande d’importer Foundation ; du coup on y perd en Code Golf (et dans les clashs de rapidité) -------------------- I think therefore I Mac
|
|
|
31 May 2016, 12:50
Message
#43
|
|
Macbidouilleur d'Or ! Groupe : Membres Messages : 2 486 Inscrit : 29 Aug 2002 Membre no 3 340 |
En fait, le problème du site sur Haskell est un peu surfait. C'est un parcours de graphe valué, mais très simplifié. Pour chaque noeud il calcule le coût pour y arriver directement par la route directe ou par l'autre route + le pont.
En pratique, c'est très décevant, l'algo Haskell compare une route à elle-même et la déclare meilleure, l'autre route étant éliminée dès le départ. Pour ce qui est des tuples, il est parfois utile de faire du pattern-machting dans l'autre sens: let point2d = (2.0, 6.5) let (x, y) = point2d C'est plus parlant. ça évite des notation pointées. Dans ce fil, j'avais dévelopé un exemple que j'ai mis sur GitHub (j'aurais du faire un gist, plutôt qu'un projet) https://github.com/jaypeeds/scala-inspired-swift, tout est dans le pouring.md. J'ai vraiment aimé le pattern-matching combiné à l'enum et la possibilité de créer un opérateur à moi. C'est un problème que Bruce Willis avait à résoudre (vu à la TV hier soir) avec deux bidons de 5 et 3 litres comment faire 4 litres. @+ J-P |
|
|
4 Jun 2016, 11:36
Message
#44
|
|
Macbidouilleur d'Or ! Groupe : Membres Messages : 2 486 Inscrit : 29 Aug 2002 Membre no 3 340 |
IBM investit dans Swift avec un server web open source en Swift. http://www.silicon.fr/ibm-pousse-langage-s...seo-139994.html
Le source est ici: https://github.com/IBM-Swift/Kitura Ceci confirme une intuition que j'avais, que Swift serait la clé d'une stack complète, du client au serveur. Petite màj... j'ai essayé, et le build de Kitura-Sample se plante... CODE [jaypee:~/workspaces/Swift/Kitura]$ make (develop) --- Fetching Kitura-Build submodule git submodule init Submodule 'Kitura-Build' (https://github.com/IBM-Swift/Kitura-Build.git) registered for path 'Kitura-Build' git submodule update --remote --merge Cloning into 'Kitura-Build'... remote: Counting objects: 413, done. remote: Compressing objects: 100% (3/3), done. remote: Total 413 (delta 0), reused 0 (delta 0), pack-reused 410 Receiving objects: 100% (413/413), 58.41 KiB | 0 bytes/s, done. Resolving deltas: 100% (208/208), done. Checking connectivity... done. Submodule path 'Kitura-Build': checked out '37667888fec95e3519c57effe96a898370d1a851' --- Running build on Darwin --- Build scripts directory: Kitura-Build/build --- Checking swift version swift --version Apple Swift version 3.0-dev (LLVM 8fcf602916, Clang cf0a734990, Swift 000d413a62) Target: x86_64-apple-macosx10.9 --- Checking swiftc version swiftc --version Apple Swift version 2.2 (swiftlang-703.0.18.8 clang-703.0.31) Target: x86_64-apple-macosx10.9 --- Checking git revision and branch git rev-parse HEAD 37fa02e6f25747fb97d0281826eec6306a74eabe git rev-parse --abbrev-ref HEAD develop --- Invoking swift build swift build error: system(["/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2016-05-31-a.xctoolchain/usr/bin/swiftc", "--driver-mode=swift", "-I", "/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2016-05-31-a.xctoolchain/usr/lib/swift/pm", "-L", "/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2016-05-31-a.xctoolchain/usr/lib/swift/pm", "-lPackageDescription", "-target", "x86_64-apple-macosx10.10", "/Users/jaypee/workspaces/Swift/Kitura/Package.swift", "-fileno", "4"], posix_spawn error: No such file or directory (2), `["/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2016-05-31-a.xctoolchain/usr/bin/swiftc", "--driver-mode=swift", "-I", "/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2016-05-31-a.xctoolchain/usr/lib/swift/pm", "-L", "/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2016-05-31-a.xctoolchain/usr/lib/swift/pm", "-lPackageDescription", "-target", "x86_64-apple-macosx10.10", "/Users/jaypee/workspaces/Swift/Kitura/Package.swift", "-fileno", "4"]`) make: *** [build] Error 1 Je crois qu'il faut encore patienter : Swift est maintenant équipé d'un gestionnaire de paquets (à la maven, sbt, gradle...) swift-build et il ne se trouve que dans les versions de dev comme la preview du 31 mai, qui elle ne contient pas le dernier compilateur. Et le mélange version stable et version dev est à l'origine du problème. Dans le message d'erreur, on voit que swift est en version 3.0-DEV mais swiftc est en 2.2. Si on sélectionne l'une ou l'autre version soit swift-build, soit switfc va manquer. Petite màj: Sur Linux, pas mieux. Le 2.2.1 ou le -DEV a toutes les commandes, mais la syntaxe et les mots-clés du constructeur Package () a évolué donc le source doit être mis à jour aussi. J-P Ce message a été modifié par Jaypee - 5 Jun 2016, 14:29. |
|
|
8 Jun 2016, 13:05
Message
#45
|
|
Macbidouilleur d'Or ! Groupe : Membres Messages : 2 486 Inscrit : 29 Aug 2002 Membre no 3 340 |
J'ai remis à niveau mon code Swift. Et il fonctionne dans le REPL d'IBM https://swiftlang.ng.bluemix.net/#/repl
CODE import Foundation
typealias State = [Int] let CAPACITIES = [3, 5, 9] print("Capacities: \( CAPACITIES )") let initialState = CAPACITIES.map({x in x * 0}) print("Initial state: \( initialState)") let glasses = 0..<CAPACITIES.count protocol StateChanger { func change(state: State) -> State } enum Move: StateChanger { case Empty(Int) case Fill(Int) case Pour(Int, Int) func change(state: State) -> State { var changed = state switch self { case .Empty(let glass): changed[glass] = 0 return changed case .Fill(let glass): changed[glass] = CAPACITIES[glass] return changed case let .Pour(from, to): let availQty = state[from] let availCap = CAPACITIES[to] - state[to] if availQty >= availCap { changed[from] = availQty - availCap changed[to] = CAPACITIES[to] } else { changed[from] = 0 changed[to] += availQty } return changed } } } // print(Move.Pour(0,2).change(state: Move.Fill(0).change(state: initialState))) infix operator ~~ { associativity left precedence 160 } // Usage: initial_state ~~ move0 ~~ move1 ~~ move2 func ~~ (left: State, right: Move) -> State { return right.change(state: left) } // print(initialState ~~ Move.Fill(0) ~~ Move.Pour(0, 2)) let TARGET = 7 protocol Enumerable { static var values:[Move] {get} } extension Move: Enumerable { static var values:[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 glasses.filter({x in x != g}) { moves.append(Move.Pour(g,h)) } } return moves } } // print(Move.values) protocol TextRepresentable { func asText() -> String } extension Move: TextRepresentable { 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))" } } } // print (Move.values.map({m in m.asText()})) typealias Path = [Move] func partition<T>(ar: [T], predicate: (T)->Bool) -> ([T],[T]) { func antiPredicate(value: T) -> Bool { return !(predicate(value)) } return(ar.filter(predicate), ar.filter(antiPredicate)) } extension Move: Equatable { } func == (left: Move, right: Move) -> Bool { return left.asText() == right.asText() } func != (left: Move, right: Move) -> Bool { return !(right == left) } 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 Move.values.filter( {x in x != lastMove!}) { var path = fromPath path.append(move) result.append(path) } } } return result } func resolve(paths: [Path], target: Int) { func isSolution(path: Path) -> Bool { return path.reduce(initialState, combine: ~~).contains(target) } let (solutions, others) = partition(ar: paths, predicate: isSolution) if (solutions.count > 0) { let _ = solutions.map({s in print("Solution: \(s.map({m in m.asText()})) -> \(s.reduce(initialState, combine: ~~))")}) } else { resolve(paths: extend(from: others), target: target) } } resolve(paths: [[]], target: TARGET) Ce message a été modifié par Jaypee - 8 Jun 2016, 13:05. |
|
|
8 Jun 2016, 13:29
Message
#46
|
|
Terminaltor Moderating Machine Groupe : Admin Messages : 24 449 Inscrit : 25 Oct 2002 Lieu : Jeumont (59) Membre no 4 319 |
Étonnant, ça ne passe pas dans Xcode, il y a plusieurs « extraneous argument label » sur les premiers arguments dans certains appels.
Ne pas mettre le label du premier argument semble effectivement la norme en Swift 2.2 https://developer.apple.com/library/ios/doc.../Functions.html -------------------- I think therefore I Mac
|
|
|
8 Jun 2016, 21:38
Message
#47
|
|
Macbidouilleur d'Or ! Groupe : Membres Messages : 2 486 Inscrit : 29 Aug 2002 Membre no 3 340 |
Le REPL IBM est en V3.0-dev, c'est sans doute ce qui fait la différence.
Les développeurs Swift ont dû faire preuve d' abnégation à chaque nouvelle version avec ce genre de changements incompatibles de syntaxe, et la V3.0 ne démérite pas... [Edit] Y'a un XCode daté du 6/6/2016 A propos du problème lui-même je crois qu'il entre dans la famille des algorithmes A*: https://www.raywenderlich.com/4946/introduc...o-a-pathfinding J-P Ce message a été modifié par Jaypee - 9 Jun 2016, 16:23. |
|
|
9 Jun 2016, 16:29
Message
#48
|
|
Macbidouilleur d'Or ! Groupe : Membres Messages : 2 486 Inscrit : 29 Aug 2002 Membre no 3 340 |
En explorant les packages Swift chez IBM, je suis tombé sur celui-ci:
https://swiftpkgs.ng.bluemix.net/package/uraimo/SwiftyGPIO Pour programmer les I/O sur le Raspberry J-P |
|
|
10 Jun 2016, 01:34
Message
#49
|
|
Terminaltor Moderating Machine Groupe : Admin Messages : 24 449 Inscrit : 25 Oct 2002 Lieu : Jeumont (59) Membre no 4 319 |
On peut quand même faire des trucs assez ésotériques
CODE var phrase = readLine()!.utf8.map{$0}, spInd = (0..<phrase.count).filter{phrase[$0] == 32 }, n = phrase.count
for i in spInd.reverse() { phrase.removeAtIndex(i) } for i in spInd.reverse() { phrase.insert(32,atIndex:n-i-1) } for (k,f) in [(UInt8(4),{(inout l:[UInt8]) in l.insert(l.removeLast(),atIndex:0)}), (3,{(inout l:[UInt8]) in l.append(l.removeFirst())}), (2,{(inout l:[UInt8]) in l=l.reverse()})] { var indices = (0..<phrase.count).filter{phrase[$0] != 32 && (phrase[$0]+8)%k == 0 }, repl = indices.map{phrase[$0]} if(repl.count>0) { f(&repl) } for i in (0..<indices.count) { phrase[indices[i]] = repl[i] } } print(String(phrase.map{Character(UnicodeScalar($0))})) -------------------- I think therefore I Mac
|
|
|
10 Jun 2016, 09:54
Message
#50
|
|
Macbidouilleur d'Or ! Groupe : Membres Messages : 2 486 Inscrit : 29 Aug 2002 Membre no 3 340 |
Ce style de code est encore très inspiré par ObjectiveC, avec ses boucles for.
S'il faut traiter chaque cellule au cas par cas, le mieux est de parcourir le tableau puis par du pattern matching, appliquer la transformation souhaitée. Petit détail, dans les déclarations de la première ligne, "phrase" est une variable (mutable) OK, mais les 2 suivantes devraient être séparées, et précédées de "let", parce qu'elles restent constantes dans le reste du code. plus loin dans la boucle, var est correct parce que la valeur est re-crée à chaque pas de la boucle. J-P Ce message a été modifié par Jaypee - 10 Jun 2016, 09:57. |
|
|
10 Jun 2016, 10:33
Message
#51
|
|
Terminaltor Moderating Machine Groupe : Admin Messages : 24 449 Inscrit : 25 Oct 2002 Lieu : Jeumont (59) Membre no 4 319 |
Ce style de code est encore très inspiré par ObjectiveC, avec ses boucles for. S'il faut traiter chaque cellule au cas par cas, le mieux est de parcourir le tableau puis par du pattern matching, appliquer la transformation souhaitée. Petit détail, dans les déclarations de la première ligne, "phrase" est une variable (mutable) OK, mais les 2 suivantes devraient être séparées, et précédées de "let", parce qu'elles restent constantes dans le reste du code. plus loin dans la boucle, var est correct parce que la valeur est re-crée à chaque pas de la boucle. J-P Je sais pour les 'let', c’est voulu pour économiser le nombre de lignes ^^ (spInd, n et même indices devraient être 'let') Le problème à résoudre était le suivant : Citation You will be given a scrambled word phrase. You must unscramble the letters to reveal the original phrase. Each phrase has been scrambled by the following process: 1) Find every 2nd letter of the alphabet in the phrase (B, D, F, etc.) and reverse their order within the phrase. 2) Find every 3rd letter of the alphabet in the phrase (C, F, I, etc.) and shift their positions one to the right, with the last letter wrapped around to the first position. 3) Find every 4th letter of the alphabet in the phrase (D, H, L, etc.) and shift their positions one to the left, with the first letter wrapped around to the last position. 4) Count the number of letters in each word, and reverse that list of numbers, re-applying the revised word lengths to the letter sequence. ex : MOSTLY HARMLESS -> MOSLRY HALMTESS -> MLSOLY HARMTESS -> MLSOHY TARMLESS -> MLSOHYTA RMLESS Et les exemples à décrypter : Code ENID OL FNE UK IFWK ONGN U RMSI HT YDAT E OMADNA ID IIAC RVFTO AR BWASRHRT HIGAI TDHE SNR VIY BRTESLOIG YRE ALBG HMTDE INI BEWA LEA ND MRMSYW EDE TVEH ITO GOHES AOTDLE MLM ENA OLSTOUG BATE Je voulais faire une solution plus courte qu’une en 15 lignes en Haskell. On peut effectivement économiser quelques 'for' (et le 'if' aussi pour le fun) : CODE var phrase = readLine()!.utf8.map{$0}, spInd = (0..<phrase.count).filter{phrase[$0] == 32 }, n = phrase.count spInd.reverse().map{phrase.removeAtIndex($0)} spInd.reverse().map{phrase.insert(32,atIndex:n-$0-1)} for (k,f) in [(UInt8(4),{(inout l:[UInt8]) in l.insert(l.removeLast(),atIndex:0)}), (3,{(inout l:[UInt8]) in l.append(l.removeFirst())}), (2,{(inout l:[UInt8]) in l=l.reverse()})] { var indices = (0..<phrase.count).filter{phrase[$0] != 32 && (phrase[$0]+8)%k == 0 }, repl = indices.map{phrase[$0]} (repl.count>0 ? f : {(inout l:[UInt8]) in})(&repl) (0..<indices.count).map{phrase[indices[$0]] = repl[$0]} } print(String(phrase.map{Character(UnicodeScalar($0))})) Là où je suis un peu déçu, c’est sur l’inférence de type, j’aurais aimé qu’il reconnaisse le type de closure sur le premier tuple, et que je puisse écrire pour les suivants juste {$0.insert($0.removeLast(),atIndex:0)} et {$0=$0.reverse()} -------------------- I think therefore I Mac
|
|
|
10 Jun 2016, 13:26
Message
#52
|
|
Macbidouilleur d'Or ! Groupe : Membres Messages : 2 486 Inscrit : 29 Aug 2002 Membre no 3 340 |
En APL, qui favorise les vecteurs (tableaux) et les indices, et qui a des opérateurs pour shifter dans les deux sens, en 3 lignes, on fait les 3 premières transfos.
Code phrase[(∨/phrase ∘.= alphabet[(0 = 2 | indices)/indices]) / ⍳⍴ phrase] ← ⌽ (∨/phrase2 ∘.= alphabet[(0 = 2 | indices)/indices]) / phrase APL a aussi la reduction par un masque logique (1 0 0 1) / 1 2 3 4 -> 1 4 Donc pour transformer 'AB CDE F' en 'A BCD EF', on va faire un masque avec la position des espaces, 0 0 1 0 0 0 1 0 qu'on retourne 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 / 1 2 3 4 5 6 7 8 donnera l'indice des espaces d'arrivée la négation du masque donne les indices des autres caractères qui sont replacés par la chaîne originale sans blanc à la dernière étape on a calculé une phrase4: Code phrase4 ← 'MLSOHY TARMLESS' phrase5 ← phrase4 phrase5[(⌽(phrase4 ≠ ' ')) / ⍳ ⍴ phrase4] ← (phrase4 ≠ ' ')/phrase4 phrase5[(⌽(phrase4 = ' ')) / ⍳ ⍴ phrase4] ← ' ' phrase5 MLSOHYTA RMLESS Note: Le iota génère les indices en partant de 0 ou 1 au choix (1 par défaut), le rho donne la longueur d'un vecteur iota rho vecteur est un idiome qui génère les indices du vecteur. le PHI soit fait la symétrie complète, soit shifte de n places vers la gauche ou vers la droite selon le signe. Une chaîne est implicitement un vecteur de caractères. PHI vecteur ou n PHI vecteur (vers la gauche si n > 0, wrapping automatique par la fin) Conclusion: On peut donc composer 4 transformations pour chiffrer et composer les inverses en ordre inverse pour déchiffrer. Le REPL APL est là: http://tryapl.org/ J-P Ce message a été modifié par Jaypee - 10 Jun 2016, 14:12. |
|
|
10 Jun 2016, 15:38
Message
#53
|
|
Terminaltor Moderating Machine Groupe : Admin Messages : 24 449 Inscrit : 25 Oct 2002 Lieu : Jeumont (59) Membre no 4 319 |
Je ne comprends pas pourquoi l’inférence de type ne fonctionne pas
Pourtant, le code suivant fonctionne bien : Code for (k,f) in [(Float(1),{(i:Float)->Float in i+1}),(2,{$0+2}),(3,{$0+3})] { print(f(k)) } Mais avec : Code for (k,f) in [(UInt8(4),{(inout l:[UInt8]) in l.insert(l.removeLast(),atIndex:0)}), (3,{$0.append($0.removeFirst())}), (2,{$0=$0.reverse()})] { // ... } J’ai droit à : Answer.swift:4:58: error: generic parameter 'Element' could not be inferred Curieux, non ? -------------------- I think therefore I Mac
|
|
|
11 Jun 2016, 07:58
Message
#54
|
|
Macbidouilleur d'Or ! Groupe : Membres Messages : 2 486 Inscrit : 29 Aug 2002 Membre no 3 340 |
Schlum,
Je ne sais toujours pas placer le curseur entre l'ambition et la capacité du langage en matière de programmation fonctionnelle. Je crains qu'il ne soit juste un peu opportuniste. Si l'anomalie dans la déduction du type de l'élément du tableau est avérée elle peut rester non-résolue pendant quelques versions Peut-être qu'il faut aller lire le source C++ de l' analyseur syntaxique pour comprendre !? ou plus simplement, écrire un test unitaire pour mettre en évidence le bug? Sinon, le type standard Zip2Sequence peut résoudre ton besoin: il génère les paires (p1, p2) avec p1 dans Array1 et p2 dans Array2 Mon expérimentation en APL m'a montré que la transformation des premières étapes ne dépend que du pas (ton k) et de l'amplitude du shift qui pourrait être un Optionnel. En APL le shift sans argument fait un miroir, et le shift avec un argument signé détermine aussi la direction. Voici donc ma solution basée sur le maquettage en APL: CODE import Foundation extension Array { func shift(by: Int?) -> [Element] { if case .Some(let amount) = by { assert(-count...count ~= amount, "Shift amount out of bounds") switch(amount) { case 0: return self default: if amount < 0 { // Right return Array(self[count + amount ..< count] + self[0 ..< (count + amount)]) } else { // Left return Array(self[amount ..< count] + self[0 ..< amount]) } } } else { return self.reverse() } } func _or_(lhs: Bool, rhs: Bool) -> Bool { return lhs || rhs } func _and_(lhs: Bool, rhs: Bool) -> Bool { return lhs && rhs } func select(only: [Bool]) -> [Element] { assert(self.count == only.count, "Selection out of bounds") var selection = [Element]() for (mask, candidate) in Zip2Sequence(only, self) { if mask { selection.append(candidate) } } return selection } func select(accept: Int -> Bool) -> [Element] { var selection = [Element]() for n in 0..<count { if accept(n) { selection.append(self[n]) } } return selection } func selectMaskWhereValue(accept: Element -> Bool) -> [Bool] { var mask = [Bool]() for value in self { mask.append(accept(value)) } return mask } func updateWhereIndex(accept: Int -> Bool, values: [Element]) -> [Element] { var selection = self var i = 0 for n in 0..<count { if accept(n) { selection[n] = values[i] i += 1 if (i == values.count) { i = 0 } } } return selection } func updateWhereValue(accept: Element -> Bool, values: [Element]) -> [Element] { var selection = self var i = 0 for n in 0..<count { if accept(self[n]) { selection[n] = values[i] i += 1 if (i == values.count) { i = 0 } } } return selection } func updateWhereMask(mask:[Bool], values: [Element]) -> [Element] { assert(self.count == mask.count, "Length error") var selection = self var i = 0 for n in 0..<count { if mask[n] { selection[n] = values[i] i += 1 if (i == values.count) { i = 0 } } } return selection } } func transform<T>(phrase: [T], which: (T) -> Bool, amplitude: Int? ) -> [T] { let mask = phrase.selectMaskWhereValue(which) if mask.filter({$0}).count > 0 { return phrase.updateWhereMask(mask, values: phrase.select(mask).shift(amplitude)) } else { return phrase } } let alphabet = Array("ABCDEFGHIJKLMNOPQRSTUVWXYZ".characters) let every2nd = alphabet.select({n in 0 == ((n + 1) % 2)}) let every3rd = alphabet.select({n in 0 == ((n + 1) % 3)}) let every4th = alphabet.select({n in 0 == ((n + 1) % 4)}) func chiffrer(clair : String) -> String { let phrase = Array(clair.characters) let phrase2 = transform(phrase, which: {every2nd.contains($0)}, amplitude: nil) let phrase3 = transform(phrase2, which: {every3rd.contains($0)}, amplitude: -1) let phrase4 = transform(phrase3, which: {every4th.contains($0)}, amplitude: 1) let maskSpaces = phrase4.selectMaskWhereValue({$0 == " "}) let maskNotSpaces = phrase4.selectMaskWhereValue({$0 != " "}) let phrase5 = phrase4.updateWhereMask(maskSpaces.shift(nil), values: [" "]) let phrase6 = phrase5.updateWhereMask(maskNotSpaces.shift(nil), values: phrase4.select(maskNotSpaces)) return String(phrase6) } chiffrer("MOSTLY HARMLESS") chiffrer("I KNOW KUNG FU") func déchiffrer(code: String) -> String { let chiffre = Array(code.characters) let spacesMask = chiffre.selectMaskWhereValue({$0 == " "}) let notSpaceMask = chiffre.selectMaskWhereValue({$0 != " "}) let clair0 = chiffre.updateWhereMask(spacesMask.shift(nil), values: [" "]) let clair1 = clair0.updateWhereMask(notSpaceMask.shift(nil), values: chiffre.select(notSpaceMask)) let clair2 = transform(clair1, which: {every4th.contains($0)}, amplitude: -1) let clair3 = transform(clair2, which: {every3rd.contains($0)}, amplitude: 1) let clair4 = transform(clair3, which: {every2nd.contains($0)}, amplitude: nil) return String(clair4) } déchiffrer("ENID OL FNE") déchiffrer("UK IFWK ONGN U") déchiffrer("RMSI HT YDAT E OMADNA ID IIAC RVFTO AR") déchiffrer("BWASRHRT HIGAI TDHE SNR VIY BRTESLOIG YRE ALBG HMTDE INI BEWA LEA ND MRMSYW EDE TVEH ITO GOHES AOTDLE MLM ENA OLSTOUG BATE") Ce qui donne pour la plus longue des phrases: TWAS BRILLIG AND THE SLITHY TOVES DID GYRE AND GIMBLE IN THE WABE ALL MIMSY WERE THE BOROGOVES AND THE MOME RATHS OUTGRABE mais est-elle vraiment plus claire ? et pour les autres: END OF LINE I KNOW KUNG FU (Au départ, bug parce pas de DHLPTX dans le message codé) IM SORRY DAVE IM AFRAID I CANT DO THAT Et pour finir, la version compactée, sans variable intermédiaire: CODE import Foundation extension Array { func shift(by: Int?) -> [Element] { // Emulates APL vertical shift operator if case .Some(let amount) = by { assert(-count...count ~= amount, "Shift amount out of bounds") switch(amount) { case 0: return self // NOP default: if amount < 0 { // Right return Array(self[count + amount ..< count] + self[0 ..< (count + amount)]) } else { // Left return Array(self[amount ..< count] + self[0 ..< amount]) } } } else { return self.reverse() // Mirror } } func select(only: [Bool]) -> [Element] { // Only Elements marked true assert(self.count == only.count, "Selection out of bounds") var selection = [Element]() for (mask, candidate) in Zip2Sequence(only, self) { if mask { selection.append(candidate) } } return selection } func select(accept: Int -> Bool) -> [Element] { // Only element with accepted index var selection = [Element]() for n in 0..<count { if accept(n) { selection.append(self[n]) } } return selection } func selectMaskWhereValue(accept: Element -> Bool) -> [Bool] { // Mask of accepted values var mask = [Bool]() for value in self { mask.append(accept(value)) } return mask } func updateWhereMask(mask:[Bool], values: [Element]) -> [Element] { // Update marked Elements, re-use values as needed assert(self.count == mask.count, "Length error") var selection = self var i = 0 for n in 0..<count { if mask[n] { selection[n] = values[i] i += 1 if (i == values.count) { i = 0 } } } return selection } } func transform<T>(phrase: [T], which: (T) -> Bool, amplitude: Int? ) -> [T] { let mask = phrase.selectMaskWhereValue(which) if mask.filter({$0}).count > 0 { return phrase.updateWhereMask(mask, values: phrase.select(mask).shift(amplitude)) } else { return phrase } } let alphabet = Array("ABCDEFGHIJKLMNOPQRSTUVWXYZ".characters) let every2nd = alphabet.select({0 == (($0 + 1) % 2)}) let every3rd = alphabet.select({0 == (($0 + 1) % 3)}) let every4th = alphabet.select({0 == (($0 + 1) % 4)}) func chiffrer(clair: String) -> String { let phrase = transform(transform(transform(Array(clair.characters), which: {every2nd.contains($0)}, amplitude: nil), which: {every3rd.contains($0)}, amplitude: -1), which: {every4th.contains($0)}, amplitude: 1) let maskSpaces = phrase.selectMaskWhereValue({$0 == " "}) let maskNotSpaces = phrase.selectMaskWhereValue({$0 != " "}) return String(phrase.updateWhereMask(maskSpaces.shift(nil), values: [" "]).updateWhereMask(maskNotSpaces.shift(nil), values: phrase.select(maskNotSpaces))) } func déchiffrer(code: String) -> String { let chiffre = Array(code.characters) let spacesMask = chiffre.selectMaskWhereValue({$0 == " "}) let notSpaceMask = chiffre.selectMaskWhereValue({$0 != " "}) return String(transform(transform(transform(chiffre.updateWhereMask(spacesMask.shift(ni l), values: [" "]).updateWhereMask(notSpaceMask.shift(nil), values: chiffre.select(notSpaceMask)), which: {every4th.contains($0)}, amplitude: -1), which: {every3rd.contains($0)}, amplitude: 1), which: {every2nd.contains($0)}, amplitude: nil)) } assert("MLSOHYTA RMLESS" == chiffrer("MOSTLY HARMLESS"), "Chiffrage incorrect") assert("UK IFWK ONGN U" == chiffrer("I KNOW KUNG FU"), "Chiffrage incorrect") assert("END OF LINE" == déchiffrer("ENID OL FNE"), "Déchiffrage incorrect") assert("I KNOW KUNG FU" == déchiffrer("UK IFWK ONGN U"), "Déchiffrage incorrect") assert("IM SORRY DAVE IM AFRAID I CANT DO THAT" == déchiffrer("RMSI HT YDAT E OMADNA ID IIAC RVFTO AR"), "Déchiffrage incorrect") assert("TWAS BRILLIG AND THE SLITHY TOVES DID GYRE AND GIMBLE IN THE WABE ALL MIMSY WERE THE BOROGOVES AND THE MOME RATHS OUTGRABE" == déchiffrer("BWASRHRT HIGAI TDHE SNR VIY BRTESLOIG YRE ALBG HMTDE INI BEWA LEA ND MRMSYW EDE TVEH ITO GOHES AOTDLE MLM ENA OLSTOUG BATE"), "Déchiffrage incorrect") Et la version V3.0 qui tourne dans le REPL IBM: CODE import Foundation extension Array { func shift(by: Int?) -> [Element] { // Emulates APL vertical shift operator if case .some(let amount) = by { assert(-count...count ~= amount, "Shift amount out of bounds") switch(amount) { case 0: return self // NOP default: if amount < 0 { // Right return Array(self[count + amount ..< count] + self[0 ..< (count + amount)]) } else { // Left return Array(self[amount ..< count] + self[0 ..< amount]) } } } else { return self.reversed() // Mirror } } func select(only: [Bool]) -> [Element] { // Only Elements marked true assert(self.count == only.count, "Selection out of bounds") var selection = [Element]() for (mask, candidate) in Zip2Sequence(_sequence1:only, _sequence2:self) { if mask { selection.append(candidate) } } return selection } func select(accept: (Int) -> Bool) -> [Element] { // Only element with accepted index var selection = [Element]() for n in 0..<count { if accept(n) { selection.append(self[n]) } } return selection } func selectMaskWhereValue(accept: (Element) -> Bool) -> [Bool] { // Mask of accepted values var mask = [Bool]() for value in self { mask.append(accept(value)) } return mask } func updateWhereMask(mask:[Bool], values: [Element]) -> [Element] { // Update marked Elements, re-use values as needed assert(self.count == mask.count, "Length error") var selection = self var i = 0 for n in 0..<count { if mask[n] { selection[n] = values[i] i += 1 if (i == values.count) { i = 0 } } } return selection } } func transform<T>(phrase: [T], which: (T) -> Bool, amplitude: Int? ) -> [T] { let mask = phrase.selectMaskWhereValue(accept: which) if mask.filter({$0}).count > 0 { return phrase.updateWhereMask(mask: mask, values: phrase.select(only: mask).shift(by: amplitude)) } else { return phrase } } let alphabet = Array("ABCDEFGHIJKLMNOPQRSTUVWXYZ".characters) let every2nd = alphabet.select(accept: {0 == (($0 + 1) % 2)}) let every3rd = alphabet.select(accept: {0 == (($0 + 1) % 3)}) let every4th = alphabet.select(accept: {0 == (($0 + 1) % 4)}) func chiffrer(clair: String) -> String { let phrase = transform(phrase: transform(phrase: transform(phrase:Array(clair.characters), which: {every2nd.contains($0)}, amplitude: nil), which: {every3rd.contains($0)}, amplitude: -1), which: {every4th.contains($0)}, amplitude: 1) let maskSpaces = phrase.selectMaskWhereValue(accept: {$0 == " "}) let maskNotSpaces = phrase.selectMaskWhereValue(accept: {$0 != " "}) return String(phrase.updateWhereMask(mask: maskSpaces.shift(by: nil), values: [" "]).updateWhereMask(mask: maskNotSpaces.shift(by: nil), values: phrase.select(only: maskNotSpaces))) } func déchiffrer(code: String) -> String { let chiffre = Array(code.characters) let spacesMask = chiffre.selectMaskWhereValue(accept: {$0 == " "}) let notSpaceMask = chiffre.selectMaskWhereValue(accept: {$0 != " "}) return String( transform(phrase: transform(phrase: transform(phrase:chiffre.updateWhereMask(mask: spacesMask.shift(by: nil), values: [" "]).updateWhereMask(mask: notSpaceMask.shift(by:nil), values: chiffre.select(only: notSpaceMask)), which: {every4th.contains($0)}, amplitude: -1), which: {every3rd.contains($0)}, amplitude: 1), which: {every2nd.contains($0)}, amplitude: nil)) } print(chiffrer(clair:"MOSTLY HARMLESS")) print(chiffrer(clair:"I KNOW KUNG FU")) print(déchiffrer(code:"ENID OL FNE")) print(déchiffrer(code:"UK IFWK ONGN U")) print(déchiffrer(code:"RMSI HT YDAT E OMADNA ID IIAC RVFTO AR")) print(déchiffrer(code:"BWASRHRT HIGAI TDHE SNR VIY BRTESLOIG YRE ALBG HMTDE INI BEWA LEA ND MRMSYW EDE TVEH ITO GOHES AOTDLE MLM ENA OLSTOUG BATE")) J-P Ce message a été modifié par Jaypee - 13 Jun 2016, 08:41. |
|
|
Nous sommes le : 23rd April 2024 - 21:49 |