Skip to content

Instantly share code, notes, and snippets.

@lexi-lambda
lexi-lambda / Control.hs
Created May 14, 2017 23:01
A reimplementation of monad-control with an alternate API
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
module Control.Monad.Trans.Control where
#lang hackett
(require (only-in racket/base for-syntax begin)
(for-syntax racket/base
racket/list
racket/syntax)
threading
syntax/parse/define
hackett/demo/pict

KSSU splits timer GUI challenge

This document presents an informal “GUI framework benchmark” along the lines of [TodoMVC][]: it is a relatively simple, well-defined problem that can be used to illustrate the strengths and weaknesses of different GUI paradigms. However, unlike TodoMVC, this problem is specifically designed to stress test state management in multi-stage modal flows, where modifications to the application state can be complex but must not be committed immediately.

The problem in question is to write a speedrunning timer for [Kirby Super Star Ultra][kssu]’s [True Arena boss rush mode][kssu-true-arena]. This is a completely meaningless problem to most people, but that’s okay—this document does not assume any familiarity with KSSU or with speedrunning timers more generally. However, I do want to go over a couple basics to provide some context on the problem being solved:

  • The True Arena is a videogame boss rush mode where the objective is to beat a series of bosses as quickly as possible.
class Monad m => FileSystemMonad m where
listDirectory' :: String -> m [String]
readFile' :: String -> m String
writeFile' :: String -> String -> m ()
instance FileSystemMonad IO where
listDirectory' = listDirectory
readFile' = readFile
writeFile' = writeFile
#!/usr/bin/env racket
#lang racket
(require net/url)
(define canonicalize-email
(let ([aliases #hash(("mflatt@cs.utah.edu" . "mflatt@racket-lang.org")
("samth@racket-lang.org" . "samth@ccs.neu.edu")
("jay@racket-lang.org" . "jay.mccarthy@gmail.com"))])
(λ (email) (hash-ref aliases email email))))
#lang racket
(require (for-syntax (for-syntax (only-in racket/private/sc
[syntax-mapping-depth syntax-pattern-variable-depth]
[syntax-mapping-valvar syntax-pattern-variable-value]))
(rename-in racket [quote-syntax quote-syntax/no-introduce])
syntax/parse/define)
syntax/parse/define)
(begin-for-syntax
#lang racket
(require (for-syntax syntax/kerncase
syntax/transformer)
syntax/parse/define)
(begin-for-syntax
(struct type:con (id) #:prefab)
(struct type:app (a b) #:prefab)
(struct type:forall (x t) #:prefab)
#lang racket
(require (for-syntax syntax/kerncase)
syntax/parse/define)
(define-simple-macro (m1 e:expr)
#:with x (local-expand #'e 'expression (kernel-form-identifier-list))
(quote-syntax x))
(define-simple-macro (m1.1 e:expr)
#lang racket/base
(require (for-syntax (only-in hackett/private/util/stx
syntax/loc/props quasisyntax/loc/props)
racket/base
racket/list
threading)
syntax/parse/define)
(provide expand-expression)
#lang racket/base
(require (for-meta 2 racket/base
syntax/parse)
(for-syntax racket/base
racket/list
racket/trace
syntax/kerncase
threading)
racket/sequence