[-*- Mode: emacs-lisp -*-]
[
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
]
[-----grammar
(gz start (prog))
(gz prog (module))
(gz module (id language-pragma-opt exports imports topdecl-star
::pr("[[language-pragma-opt]]module [[id]] [[exports]] where{\n[[imports]]\n"
"[[topdecl-star('',';\n','\n')]]}\n\n")))
(gz language-pragma ( :language-pragma f id-non-star j
::pr
("{-# LANGUAGE [[id-non-star('',',','')]] #-}\n")))
(gz exports (f export-star j
::pr("[[export-star('(',', ',')')]]")) (:export-everything ::pr("")))
(gz export (id)
(f :module-export id j ::pr("module [[id]]"))
)
(gz imports (f import-star j
::pr("[[import-star('',';\n',';\n')]]")))
(gz import(id ::pr( "import [[id]]"))
(f :qualified (original-name ::is id) (new-name ::is id) j
::pr ( "import qualified [[original-name]] as [[new-name]]"))
(f :specific id id-non-star j
::pr ("import [[id]][[id-non-star('(',',',')')]]"))
)
(gz type-class (f decl-mark (class-name ::is id) :type-class context-opt id-non-plus f type-class-decl-star j j
::pr("class [[context-opt]][[class-name]] [[id-non-plus('',' ','')]] where{\n"
"[[type-class-decl-star('',';\n','\n')]]}")))
(gz topdecl (decl) (data)(type-synonym)(newtype)(instance)(type-class))
(gz type-class-decl (type-signature)(decl))
(gz type-signature (f :tysig name ret-type-and-params j
::pr("[[name]] :: [[ret-type-and-params]]")))
(gz instance (f :instance (type ::is id) (name ::is simpletype) decls j
::pr ("instance [[type]] ([[name]]) where [[decls]]")))
[(gz instance (f :instance context-opt (type ::is id) simpletype-plus :x decls j
::pr ("instance [[context-opt]][[type]] [[simpletype-plus('(',')(',')')]] where [[decls]]")))]
(gz newtype (f decl-mark id :newtype type-vars-opt constr deriving-opt j
::pr("newtype [[id]] [[type-vars-opt]] = [[constr]][[deriving-opt]]")))
(gz deriving (:deriving f id-non-plus j
::pr(" deriving [[id-non-plus('(',', ',')')]]")))
(gz id-non (id))
(gz type-synonym (f decl-mark id :type-synonym type-vars-opt type j
::pr("type [[id]] [[type-vars-opt]] = [[type]]")))
(gz data (f decl-mark id :data type-vars-opt constrs deriving-opt j ::pr("data [[id]] [[type-vars-opt]] = [[constrs]][[deriving-opt]]")))
(gz simpletype (f id-non-plus j ::pr ("[[id-non-plus('',' ','')]]")))
(gz type-vars (:args f id-non-star j ::pr ("[[id-non-star('',' ','')]]")))
(gz constrs(constr-star ::pr("[[constr-star('',' | ','')]]"))
)
(gz field-type-and-param (f param type j
::pr("[[param]] :: [[type]]")))
(gz type-and-param ( f param type j ::pr("[[type]]")))
(gz constr(positional-constructor) (field-label-constructor) )
(gz field-label-constructor(f type-ctor :field field-type-and-param-star j
::pr("[[type-ctor]][[field-type-and-param-star('{',', ','}')]]")))
(gz decls ( decl-star ::pr("{[[decl-star('\n',';\n','\n')]]}\n")))
(gz context (:context f a-context-plus j ::pr
("[[a-context-plus('(',', ',')')]] => ")))
(gz a-context [(f (type ::is id) id-non-plus j
::pr("[[type]] [[id-non-plus('',' ','')]]"))]
(f (class ::is id) type-plus j
::pr("[[class]] [[type-plus('(',')(',')')]]"))
)
(gz forall (:forall f id-non-plus j
::pr("forall [[id-non-plus('',' ','')]] . ")))
(gz ret-type-and-params
(type f type-and-param-star j forall-opt context-opt
::pr("[[forall-opt]][[context-opt]][[type-and-param-star('',' \x2d> ','')]]"
(::c "if(my_type_and_param_star->v.size()>0)out(' \x2d> ');")
"[[type]]")))
(gz decl (f decl-mark name :fun ret-type-and-params expr j
::pr("[[name]] :: [[ret-type-and-params]];\n"
"[[name]]"
(::c "for(many_trees::const_iterator pos = my_ret_type_and_params->my_type_and_param_star->v.begin();pos!= my_ret_type_and_params->my_type_and_param_star->v.end();++pos){"
"const tr_type_and_param* t=dynamic_cast(*pos);"
"assert(t);"
"out(' ');"
"t->my_param->print();" "}")
" = [[expr]]"))
(f decl-mark name :fun :no-sig ret-type-and-params expr j
::pr("[[name]]"
(::c "for(many_trees::const_iterator pos = my_ret_type_and_params->my_type_and_param_star->v.begin();pos!= my_ret_type_and_params->my_type_and_param_star->v.end();++pos){"
"const tr_type_and_param* t=dynamic_cast(*pos);"
"assert(t);"
"out(' ');"
"t->my_param->print();" "}")
" = [[expr]]"))
(f decl-mark name :simple expr j
::pr("[[name]] = [[expr]]"))
)
(gz name (id))
(gz positional-constructor ["this one is sketchy"]
(type-ctor ::pr("[[type-ctor]]"))
(f type-ctor typepls-opt j
::pr("[[type-ctor]][[typepls-opt]]"))
(f :tuple type-plus j
::pr("[[type-plus('(',', ',')')]]"))
)
(gz pattern
(id)
(f pattern-ctor pattern-star j
::pr ("([[pattern-ctor]] [[pattern-star('',' ','')]])"))
(f pattern-ctor :fpat f fpat-star j j
::pr ("[[pattern-ctor]][[fpat-star('{',', ','}')]]"))
(f :ptuple pattern-plus j [pattern-plus cuz :nil exists for empty lists]
::pr("[[pattern-plus('(',', ',')')]]"))
(f :plist pattern-plus j [pattern-plus cuz :nil exists for empty lists]
::pr("[[pattern-plus('\x5b',', ','\x5d')]]"))
(f :pchar astring j ::pr("(\x27[[astring]]\x27)"))
(f :pstring astring j ::pr("\x22[[astring]]\x22"))
(f :as id pattern j ::pr("[[id]]@[[pattern]]"))
)
(gz pattern-ctor (id) (:cons ::pr ("(:)")) (:nil ::pr ("[]")))
(gz fpat (f (variable ::is id) pattern j
::pr("[[variable]] = [[pattern]]")))
(gz type
(f :fn ret-type-and-params j ::pr ("([[ret-type-and-params]])")) (:unit ::pr("()"))
(positional-constructor))
(gz typepls (paren-type-plus))
(gz paren-type (type ::pr( "([[type]])"))
(f :strict type j ::pr("!([[type]])"))
(f :generic id j ::pr (" [[id]] ")))
(gz type-ctor(id)(:list ::pr ("[]"))(:nondet ::pr ("[]")))
(gz param (pattern))
(gz qastring (astring ::pr("\x22[[astring]]\x22")))
(gz expr (id) (:mcons ::pr ("(:)")) [(:nil ::pr ("[]"))]
[(f :pipe expr-plus j ::pr[("[[expr-star('(',' $ ',')')]]")]
(
(::c "for(many_trees::const_iterator pos = my_expr_plus->v.begin();"
"pos!=my_expr_plus->v.end();++pos){")
"("
(::c "(*pos)->print();" "}")
(::c "for(many_trees::const_iterator pos = my_expr_plus->v.begin();"
"pos!=my_expr_plus->v.end();++pos){")
")"
(::c "}")
)
)]
(f :join expr-plus j ::pr("[[expr-plus('(',' >>= ',')')]]"))
(f :rpipe expr-plus j ::pr[("[[expr-star('(',' $ ',')')]]")]
(["http;//gcc.gnu.org/bugzilla/show_bug.cgi?id=11729"]
(::c "for(many_trees::reverse_iterator pos = my_expr_plus->v.rbegin();"
"pos!=my_expr_plus->v.rend();++pos){")
"("
(::c "(*pos)->print();" "}")
(::c "for(many_trees::const_iterator pos = my_expr_plus->v.begin();"
"pos!=my_expr_plus->v.end();++pos){")
")"
(::c "}")
)
)
(f :rcompose expr-plus j ::pr
[("[[expr-plus('(',' . ',')')]]")]
("("
(::c "for(many_trees::reverse_iterator pos = my_expr_plus->v.rbegin();"
"pos!=my_expr_plus->v.rend();++pos){")
(::c "if(pos!=my_expr_plus->v.rbegin())")
" . "
(::c "(*pos)->print();" "}")
")"
)
)
(f :cc expr-star j ::pr ("[[expr-star('(',' ++ ',')')]]"))
(qastring)
(f :lit astring j ::pr("[[astring]]"))
(f :ty type expr j ::pr("([[expr]] :: [[type]])"))
(f (fun-name ::is expr) expr-star j
::pr ("([[fun-name]][[expr-star(' ',' ','')]])"))
[(f :construct ctor expr-star j
::pr ("([[ctor]] [[expr-star('',' ','')]])"))]
(f :do stmt-star j ::pr("(do{\n[[stmt-star(' ','\n ','\n')]]})"))
(f :case expr alt-star j
::pr("(case [[expr]] of {\n[[alt-star(' ',';\n ','\n')]]})"))
(f :case expr alt-star :else (underbar ::is expr) j
["the else is there so the grammar does not have a reduce/reduce conflict"]
::pr("(case [[expr]] of {\n[[alt-star(' ',';\n ',';\n')]]"
" _ -> [[underbar]]\n"
"})"))
(f :lcase alt-star j
::pr("(\x5clambda_case_var ->"
"case lambda_case_var of {\n"
"[[alt-star(' ',';\n ','\n')]]})"))
(f :lcase alt-star :else (underbar ::is expr) j
::pr("(\x5clambda_case_var ->"
"case lambda_case_var of {\n"
"[[alt-star(' ',';\n ',';\n')]]"
" _ -> [[underbar]]\n"
"})"))
(f :let decl-star expr j
::pr("(let {[[decl-star('\n',';\n','\n')]]}\n in [[expr]])"))
(f :cfd expr assignments-star j
::pr("([[expr]][[assignments-star('{',', ','}')]])"))
[(f :compose (a ::is expr) (b ::is expr) j ::pr("((.)[[a]] [[b]])"))]
[(:compose ::pr ("(.)"))]
[(f :compose expr-plus j ::pr ("[[expr-plus('(',' . ',')')]]"))]
(f :mlist expr-star j ::pr("[[expr-star('\x5b',', ','\x5d')]]"))
(f :cons-list expr-star j ::pr("[[expr-star('(',':',')')]]"))
(f :mtuple expr-star j ::pr("[[expr-star('(',', ',')')]]"))
(:nothing ::pr ("()"))
(f :lambda name ret-type-and-params expr j
::pr("(let {[[name]] :: [[ret-type-and-params]];\n"
"[[name]]"
(::c "for(many_trees::const_iterator pos = my_ret_type_and_params->my_type_and_param_star->v.begin();pos!= my_ret_type_and_params->my_type_and_param_star->v.end();++pos){"
"const tr_type_and_param* t=dynamic_cast(*pos);"
"assert(t);"
"out(' ');"
"t->my_param->print();" "}")
" = [[expr]]} in [[name]])"))
(f :lambda-simple id-non expr j
[recommended only for reordering arguments to functions
and other simple expressions]
[only one variable to keep it simple]
::pr ("(\x5c[[id-non]] -> [[expr]])"))
)
(gz assignments (f id expr j ::pr("[[id]] = [[expr]]")))
(gz stmt (expr ::pr("[[expr]];"))
(f ":=" pattern type expr j ::pr("[[pattern]] :: [[type]] <- [[expr]];"))
(f :dlet decl-star j ::pr ("let {[[decl-star('\n',';\n','\n')]]};"))
)
(gz alt (f pattern expr-or-gpat j
::pr("[[pattern]][[expr-or-gpat]]")))
(gz expr-or-gpat
(expr ::pr ("-> [[expr]]"))
(where-opt :gpats pred-expr-star [silly lookahead limitation]
::pr ("\n[[pred-expr-star('','','')]] [[where-opt]]"
)))
(gz pred-expr ( f (pred ::is expr) (do ::is expr) j
::pr ("| [[pred]]\n -> [[do]]\n")))
(gz where (:where decls ::pr ("where [[decls]]")))
(gz decl-mark (":"))
]
Main :language-pragma
(
ScopedTypeVariables
[PatternSignatures]
GeneralizedNewtypeDeriving
)
(main)
(
Array
System
Char
IO
Control.Monad.State
Control.Exception
Monad
Random
Data.List
(:qualified Data.Set Set)
(:qualified Data.Map Map)
Maybe
Data.Array.ST
Control.Monad.ST
)
(: main :fun (IO :unit)()
(:do
[(hPutStrLn stderr rcs-code)]
(setStdGen(mkStdGen 1))
(:join
getArgs
(:lcase
((:plist(:pstring "nothing"))(return :nothing))
((:plist(:pstring "show-chords")(num-actions))(show-chords(read num-actions)))
))))
(: map-tuple :fun(:tuple(b)(b))((fn(:fn(b)((x(a)))))
(x(:tuple(a)(a))))
(:mtuple (fn (fst x))(fn (snd x))))
(: apply-first :fun(:tuple(b)(c))((fn(:fn(b)((_(a)))))
(x(:tuple(a)(c))))
(:mtuple (fn (fst x))(snd x)))
(: apply-second :fun(:tuple(c)(b))
((fn(:fn(b)((_(a)))))(x(:tuple(c)(a))))
(:mtuple (fst x)(fn (snd x))))
(: zip-check-same-length :fun (:list(:tuple(a)(b)))
((x1(:list(a)))(x2(:list(b))))
(:case
(:mtuple x1 x2)
((:ptuple(:nil)(:nil))(:mlist))
((:ptuple(:cons(a)(arest))
(:cons(b)(brest)))
(:mcons(:mtuple a b)
(zip-check-same-length arest brest)))))
(: zipWith-check-same-length :fun (:list(c))
((f(:fn(c)((x1(a))(x2(b)))))(x1(:list(a)))
(x2(:list(b))))
(:case
(:mtuple x1 x2)
((:ptuple(:nil)(:nil))(:mlist))
((:ptuple(:cons(a)(arest))
(:cons(b)(brest)))
(:mcons
(f a b)
(zipWith-check-same-length f arest brest)))))
(: zip-map :fun (:list(:tuple a b))
((f(:fn b ((x a)))) (l(:list a)))
(zip l (map f l)))
(: flip-tuple :fun (:tuple b a) ((x(:tuple a b)))
(:mtuple (snd x)(fst x)))
(: show-list :fun (IO :unit)((l(:list a))):context ((Show a))
(:rpipe l (map show) unlines putStr))
(: compare-zipped :fun (:fn Ordering ((x(:tuple a b))(y(:tuple a b)))) () :context ((Ord b))
(curry(:rcompose (map_tuple snd)(uncurry compare))))
(: take-while-plus :fun (:tuple(:list a)(Maybe a))
((p(:fn Bool ((x a))))
(l(:list a)))
(:case l
((:nil)(:mtuple(:mlist)Nothing))
((:cons(h)(t))
(:case(p h)
((False)(:mtuple(:mlist)(Just h)))
((_)(:let
(: answer :simple
(take-while-plus p t))
(:mtuple
(:mcons h (:rpipe answer fst))
(snd answer))))))))
(: random-from-list :fun (IO a) ((l (:list a)))
(:join
(:rpipe
(:mtuple 0
(:rpipe l length pred)
)
randomR
getStdRandom
)
(:rcompose
(!! l)
return)))
(: rcs-code :fun String ()
"$Id: chords.ll,v 1.10 2010/12/05 11:58:07 kenta Exp kenta $")
(: Button :data (Thumb Tposition)(Finger Fnumber):deriving (Show Eq))
(: Direction :data Up Down :deriving(Show Eq))
(: Command :data (Key Hand Button Direction) Beat :deriving(Show Eq))
(: Tposition :newtype (Tposition Int):deriving(Show Eq Ord Ix))
(: Hstate :data (Hstate Tstate Fstate):deriving (Show Eq))
(: Tstate :type-synonym (Array Hand (Maybe Tposition)))
(: Hand :newtype (Hand Int):deriving(Eq Ord Show Ix))
(: Hand-finger :type-synonym (:tuple Hand Fnumber))
(: Fstate :type-synonym (Array Hand-finger Direction))
(: Fnumber :newtype (Fnumber Int):deriving(Eq Ord Show Ix))
(: t-bounds :fun (:tuple Tposition Tposition)()
(:mtuple (Tposition 1)(Tposition 2)))
(: f-bounds :fun (:tuple Hand-finger Hand-finger)()
(:mtuple (:mtuple (fst h-bounds) (Fnumber 1))
(:mtuple (snd h-bounds) (Fnumber 2))))
(: h-bounds :fun (:tuple Hand Hand)()
(:mtuple (Hand 1)
(Hand 2)))
(: tmoves-one-hand :fun (:list Command) ((hand Hand)(old(Maybe Tposition)))
(:case old
((Just p)(:mlist(Key hand (Thumb p) Up)))
:else
(:do
(:= t Tposition all-thumbs)
(return (Key hand (Thumb t) Down))
)))
(: all-thumbs :fun (:list Tposition)()
(range t-bounds))
(: flip-dir :fun Direction ((d Direction))
(:case d
(Up Down)
(Down Up)))
(: finger-moves :fun (:list Command) ((fs Fstate))
(:do
(:= (:ptuple (:ptuple hand finger) dir)
(:tuple Hand-finger Direction)(assocs fs))
(return (Key hand (Finger finger) (flip-dir dir)))
))
(: thumb-moves :fun(:list Command)((ts Tstate))
(:do
(:= (:ptuple hand thumb)
(:tuple Hand (Maybe Tposition))
(assocs ts))
(tmoves-one-hand hand thumb)))
(: empty-thumb :fun Tstate ()
(listArray h-bounds (repeat Nothing)))
(: empty-fingers :fun Fstate ()
(listArray f-bounds (repeat Up)))
(: empty-hand :fun Hstate ()
(Hstate empty-thumb empty-fingers))
(: ma :fun (Array i v)((a(Array i v))(x i)(y v))
:context((Ix i))
(// a (:mlist(:mtuple x y))))
(: fguard :fun (m :unit) ((pred Bool))
:context ((Monad m))
(:case pred
(True (return :nothing))
(False (fail "fail"))))
(: execute :fun (m Hstate) ((c Command)((Hstate thumb finger)Hstate))
:context((Monad m))
(:case c
(Beat (return(Hstate thumb finger)))
((Key hand button dir)
(:case (:mtuple button dir)
((:ptuple(Thumb t)Down)(:do
(:rpipe hand (! thumb) isNothing fguard)
(return
(Hstate (ma thumb hand (Just t)) finger))
))
((:ptuple(Thumb t)Up)(:do
(:rpipe hand (! thumb) isJust fguard)
(return
(Hstate (ma thumb hand Nothing) finger))
))
((:ptuple(Finger f)newstate)(:do
(:dlet
(: hf :fun Hand-finger ()(:mtuple hand f)))
(:rpipe hf (! finger) (/= newstate) fguard)
(return(Hstate thumb
(ma finger hf newstate)))
))
))
))
(: all-moves :fun (:list Command) (((Hstate t f)Hstate))
(:mcons Beat(++ (finger-moves f)(thumb-moves t))))
(: Mstate :type-synonym :args (a) (State (Maybe Hstate) a))
(: execute-in-monad :fun (Mstate :unit) ((c Command))
(:join get (:rcompose (execute-out-monad c) put)))
(: execute-out-monad :fun (m Hstate) ((c Command)
(oldm(m Hstate)))
:context((Monad m))
(:join oldm (execute c)))
(: run-through :fun (Maybe Hstate) ((c (:list Command)))
(execState (mapM- execute-in-monad c) (Just empty-hand)))
(: do-one :fun (:list(:tuple Hstate Command))((x Hstate))
(:do
(:= move Command (all-moves x))
(return (:mtuple (fromJust(execute move x)) move))
))
(: do-several :fun (:list(:list Command))
((n Int)(x Hstate))
(:case (compare n 0)
(EQ (return (:mlist)))
(GT
(:do
(:= (:ptuple new-state did-move)(:tuple Hstate Command)
(do-one x))
(:= rest (:list Command)(do-several (pred n) new-state))
(return (:mcons did-move rest))))))
(: good-end-state :fun Bool ((c(:list Command)))
["all fingers up at the end"]
(== (Just empty-hand) (run-through c)))
(: state-tuples :fun (:list (Maybe Hstate)) ((c(:list Command)))
(:rpipe
(scanl (flip execute-out-monad) (Just empty-hand) c)
tail
init))
(: no-beats :fun Filter ()
(:rcompose (map (/= Beat)) and))
(: and-preds :fun Bool ((fs(:list(:fn Bool ((x a)))))(x a))
:forall(a)
(and
(:do
(:= f (:fn Bool((x a))) fs)
(return (f x)))))
(: in-state :fun Bool ((p(:fn Bool ((s Hstate))))
(c(:list Command)))
(:rpipe c state-tuples
(map (:rcompose fromJust p))
and))
(: Filter :type-synonym (:fn Bool ((c (:list Command)))))
(: always-down-1 :fun Filter () ["there is always at least one finger down"]
(in-state (/= empty-hand) ))
(: always-down :fun Bool ((c(:list Command)))
(&&(/= c (:mlist Beat))
(always-down-1 c)))
(: one-finger :fun Bool (((Hstate _ fingers)Hstate))
["avoid both the index and middle finger both down on one hand"]
(and (map (one-finger-per-hand fingers) (range h-bounds))))
(: one-finger-per-hand :fun Bool ((finger Fstate)(target Hand))
(:case
(:do
(:= (:ptuple(:ptuple hand _)Down)
(:tuple Hand-finger Direction)(assocs finger))
(guard (== hand target))
(return :nothing)
)
((:nil) True)
((:cons(_)(:nil))True)
:else False))
(: Thumb-command :data Thumb-beat (Thumb-specific Tposition Direction):deriving (Show))
(: Thumb-state :data Thumb-down (Thumb-up (Maybe Tposition)) :deriving (Show))
(: filter-thumb :fun (:list Thumb-command)((target Hand)(c Command))
(:case c
(Beat(return Thumb-beat))
((Key hand (Thumb i) dir)
:gpats ((== hand target)(return (Thumb-specific i dir))))
:else (:mlist)
))
(: move-thumb :fun (m Thumb-state) ((oldm (m Thumb-state))(next Thumb-command))
:context((Monad m))
(:do
(:= old Thumb-state oldm)
(:case (:mtuple old next)
((:ptuple Thumb-down Thumb-beat)(return Thumb-down))
((:ptuple Thumb-down (Thumb-specific i Up))(:rpipe i Just Thumb-up return))
((:ptuple Thumb-down (Thumb-specific _ Down))(error "more down on down"))
((:ptuple (Thumb-up Nothing) Thumb-beat)(return (Thumb-up Nothing)))
((:ptuple (Thumb-up Nothing) (Thumb-specific _ Down))(return Thumb-down))
((:ptuple (Thumb-up(Just _)) Thumb-beat)(return (Thumb-up Nothing)))
((:ptuple (Thumb-up _)(Thumb-specific _ Up))(error "more up on up"))
((:ptuple (Thumb-up(Just i)) (Thumb-specific j Down))
(:case (== i j)
(True(return Thumb-down))
:else
(fail "moving thumb too fast"))))))
(: test-thumb-minor :fun (Maybe Thumb-state)((c(:list Thumb-command)))
(foldl move-thumb (Just(Thumb-up Nothing)) c))
(: from-empty :fun (:list(:list Command))((n Int))
(do-several n empty-hand))
(: test-thumb-one-hand :fun (Maybe Thumb-state)((c(:list Command))(h Hand))
(:rpipe
c
(map (filter-thumb h))
concat
test-thumb-minor))
(: test-thumb :fun Bool ((c(:list Command)))
(and (map (:rcompose(test-thumb-one-hand c)isJust) (range h-bounds))))
(: show-chords :fun (IO :unit)((num-actions Int))
(:rpipe
[(enumFromTo 1 num-actions)
(concatMap from-empty)]
num-actions from-empty
(filter (and-preds
(:mlist
always-down
[(in-state one-finger)]
test-thumb
one-beat-at-a-time
good-end-state)))
length print
[show-list]))
(: head-one-beat-at-a-time :fun Bool ((c(:list Command)))
(/= (:mlist Beat Beat)(take 2 c)))
(: one-beat-at-a-time :fun Bool ((c(:list Command)))
(:rpipe
c
tails
(map head-one-beat-at-a-time)
and))