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é 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.
Go to the top of the page
 
+Quote Post
schlum
posté 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 wink.gif


--------------------
          I think therefore I Mac          
Go to the top of the page
 
+Quote Post
Jaypee
posté 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.
Go to the top of the page
 
+Quote Post
Jaypee
posté 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
Go to the top of the page
 
+Quote Post
schlum
posté 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



Citation (Jaypee @ 14 Dec 2014, 11:31) *
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 wink.gif


--------------------
          I think therefore I Mac          
Go to the top of the page
 
+Quote Post
Jaypee
posté 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
Go to the top of the page
 
+Quote Post
schlum
posté 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 laugh.gif

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          
Go to the top of the page
 
+Quote Post
yponomeute
posté 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
Go to the top of the page
 
+Quote Post
schlum
posté 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



Citation (yponomeute @ 30 May 2016, 10:38) *
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 laugh.gif

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          
Go to the top of the page
 
+Quote Post
Jaypee
posté 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.
Go to the top of the page
 
+Quote Post
yponomeute
posté 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
Go to the top of the page
 
+Quote Post
schlum
posté 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



Citation (Jaypee @ 31 May 2016, 07:19) *
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 » wink.gif
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.


Citation (Jaypee @ 31 May 2016, 07:19) *
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 wink.gif

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é) biggrin.gif


--------------------
          I think therefore I Mac          
Go to the top of the page
 
+Quote Post
Jaypee
posté 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
Go to the top of the page
 
+Quote Post
Jaypee
posté 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.
Go to the top of the page
 
+Quote Post
Jaypee
posté 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.
Go to the top of the page
 
+Quote Post
schlum
posté 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          
Go to the top of the page
 
+Quote Post
Jaypee
posté 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.
Go to the top of the page
 
+Quote Post
Jaypee
posté 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 smile.gif
J-P
Go to the top of the page
 
+Quote Post
schlum
posté 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 laugh.gif

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          
Go to the top of the page
 
+Quote Post
Jaypee
posté 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.
Go to the top of the page
 
+Quote Post
schlum
posté 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



Citation (Jaypee @ 10 Jun 2016, 10:54) *
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          
Go to the top of the page
 
+Quote Post
Jaypee
posté 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.
Go to the top of the page
 
+Quote Post
schlum
posté 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 sad.gif

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          
Go to the top of the page
 
+Quote Post
Jaypee
posté 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.
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 : 23rd April 2024 - 21:49