AI 资讯
D’une image nommée .iso à un premier probe en Haskell
À propos de cette série. Cette série raconte la construction progressive, en Haskell, d’outils consacrés à l’étude et à la transformation des formats binaires employés par les jeux FromSoftware sur PlayStation 3. Elle prend pour premier corpus la version PlayStation 3 originale de Demon’s Souls et avance par enquêtes reproductibles : observer une structure, établir ce qui est documenté, distinguer les faits des hypothèses, puis implémenter la plus petite capacité nécessaire à l’étape suivante. Dans ce premier article, nous allons déterminer ce qu’un fichier nommé image.iso permet réellement d’affirmer. Nous commencerons par observer ses métadonnées au moyen de lectures précisément bornées, avant de reproduire cette reconnaissance dans un prototype direct écrit en Haskell. Le nom image.iso constitue une hypothèse, non une preuve de format. Une extension est une convention du système de fichiers hôte ; elle ne garantit pas le contenu du fichier. Nous allons donc rechercher une structure définie par ISO 9660, lire plusieurs champs précis, puis reconnaître deux informations supplémentaires : un marqueur Joliet et un enregistrement propre aux disques PlayStation 3. Notre périmètre restera strictement en lecture seule. Nous ne monterons pas l’image, ne parcourrons aucun répertoire, n’extrairons rien, ne déchiffrerons rien et n’écrirons aucun octet. À la fin, notre prototype affichera seulement : ps3.product-id=BLES-00932 iso9660.volume-id=PS3VOLUME iso9660.logical-block-size=2048 joliet.level=1 Ces quatre lignes sont un résultat de reconnaissance borné, non un certificat de conformité de l’image entière. De la position logique à l’offset Un fichier binaire est une suite d’octets. Nous appelons offset la position, comptée depuis zéro, d’un octet dans cette suite. ISO 9660 organise les informations qui nous intéressent en secteurs logiques de 2 048 octets. Une LBA ( Logical Block Address , adresse logique de bloc) est le numéro d’un tel secteur : le secteur de LBA 0 commenc
开发者
⚡️ Leverage Go superpowers with PureScript! Native speed w/ absolute type safety
When you combine the absolute safety and elegance of a purely functional language with the raw execution speed of a modern low-level language, it's like discovering that space and time are inextricably linked: a whole new dimension opens up to you. In my previous article , I introduced phpurs , a compiler backend that brings the absolute mathematical safety of PureScript to the 70% of the web that still runs on PHP. The goal was to prove that we do not have to sacrifice modern safety and ergonomics just because we target a runtime that is, at first glance, not the most natural. Today, we are looking at the exact opposite end of the spectrum. If PHP was about ultimate portability and legacy compatibility, what happens when we want pure, raw metal speed ? What happens when we want true multi-core concurrency, static native binaries, and a garbage collector designed for extreme high-throughput? Say hello to one of my recent projects: gopurs , a super-optimized PureScript-to-Go compiler. And let me spoil the end of the story right away: by combining the high-level semantic purity of PureScript with the raw execution force of modern Go, the final compiled code matches Chez Scheme speed on pure computational benchmarks. Yes, Chez Scheme, one of the absolute historical champions of functional AOT compilation (i.e., decades of compiler optimizations). This will be a shorter article in the series, but here is a quick version of the story... Breaking the AOT ceiling: how TAST changed everything Historically, compiling highly polymorphic functional languages (like PureScript or Haskell) to statically typed languages like Go has often been a nightmare. Older attempts often relied on mapping everything to Go's interface{} (or any ). It works, but it's a performance sacrifice. Every primitive value you assign to an interface{} is boxed and escapes to the heap , generating massive pressure on Go's Garbage Collector. To solve this, gopurs initially used a flat Value struct (a tagge
AI 资讯
Benchmarking Zippers in Haskell
In the previous post , we explored zippers and their applications in functional programming. In this post, we benchmark their performance against a root-based approach. Two Approaches We define a simple tree data structure and the naive root-based approach for traversing and modifying the tree. data Tree = Atom ! Int ! String | Object ! Int ! ( Map String Tree ) deriving ( Show , Eq , Generic , NFData ) access :: [ String ] -> ( Tree -> Tree ) -> Tree -> Tree access [] f t = f t access ( k : ks ) f ( Object vers ts ) = Object vers $ Map . alter modifyChild k ts where modifyChild Nothing = error "Invalid path to access" modifyChild ( Just child ) = Just $ access ks f child access _ _ _ = error "Invalid path to access" Then we implement the zipper data structure and its operations for traversing and modifying the tree. data Zipper = Zipper { focus :: ! Tree , breadcrumbs :: [ Crumb ] } deriving ( Show , Eq , Generic , NFData ) type Move = Zipper -> Zipper data Crumb = Crumb { holeKey :: ! String , storedVers :: ! Int , siblings :: ! ( Map String Tree ) } deriving ( Show , Eq , Generic , NFData ) goDown :: String -> Zipper -> Zipper goDown k ( Zipper ( Object vers ts ) bs ) | ( Just child , siblings' ) <- Map . updateLookupWithKey ( \ _ _ -> Nothing ) k ts = Zipper child ( Crumb k vers siblings' : bs ) goDown k ( Zipper f _ ) = error $ "Cannot go to child '" ++ k ++ "' of tree: " ++ show f goUp :: Zipper -> Zipper goUp ( Zipper t ( Crumb key vers siblings' : bs )) = Zipper ( Object vers ( Map . insert key t siblings' )) bs goUp ( Zipper _ [] ) = error "Already at the top" Benchmark Design Each benchmark performs 100,000 operations. Three full trees are generated with the following shapes: Depth × width nodes Children per Map 5 × 16 1,118,481 16 10 × 4 1,398,101 4 20 × 2 2,097,151 2 Here, depth counts edges from the root. All three trees have exactly 1,048,576 leaves, but their shapes differ. The workloads are: Random lookup. Choose a path by selecting its depth uniform
开源项目
🔥 simplex-chat / simplex-chat - SimpleX - the first messaging network operating without user
GitHub热门项目 | SimpleX - the first messaging network operating without user identifiers of any kind - 100% private by design! iOS, Android and desktop apps 📱! | Stars: 11,848 | 191 stars today | 语言: Haskell
AI 资讯
Building a Four-Bar Linkage Mechanism Simulator in Haskell
Most developers know Haskell as a language for functional programming, type safety, compilers, parsers, and beautiful mathematical abstractions. But can Haskell also be used to build an interactive engineering simulator? That was the motivation behind my project: Four-Bar Mechanism Haskell Simulator Repository: https://github.com/mohammadijoo/Four-Bar-Mechanism-Haskell This project is a browser-backed desktop-style GUI application written in Haskell. It visualizes, classifies, and animates a planar four-bar linkage mechanism, which is one of the most classical mechanisms in mechanical engineering, kinematics, and machine design. The GUI is built with Threepenny-GUI , so the interface runs in a local browser window, while the mathematical model and mechanism logic remain written in Haskell. For me, the interesting part was not only drawing a moving linkage. It was about connecting mechanism design theory , computational geometry , and functional programming in one small educational simulator. What is a four-bar linkage? A four-bar linkage is a closed-loop mechanical system made from four rigid links connected by four revolute joints. In this project, the four links are: Symbol Name Description g Ground link Fixed distance between pivots A and B a Input link Rotating link from A to moving pivot C b Output link Link from fixed pivot B to moving pivot D f Floating link / coupler Link connecting moving pivots C and D The fixed pivots are placed at: A = ( 0 , 0 ) , B = ( g , 0 ) The input link rotates by angle α . Therefore, point C can be computed directly as: C = ( a cos α ,; a sin α ) Point D is more interesting. It must satisfy two geometric distance constraints: ∣ D − C ∣ = f ∣ D − B ∣ = b So the simulator solves the position of point D using a circle-intersection method. One circle is centered at C with radius f . The other circle is centered at B with radius b . Where those two circles intersect, the mechanism can close. That is the basic geometric heart of the sim