theory hawk imports Main "HOL-Library.BNF_Corec" begin type_synonym time=nat text \Define the type of signals as a codatatype (i.e., as a stream of elements)\ codatatype 'a signal = Signal (head: 'a) (rest: "'a signal") for map: lift \ \The canonical map operator on the \ text \Conversion function from the codatatype view to the view as a function @{typ \time \ 'a\}\ fun at :: "'a signal \ time \ 'a" where "at (Signal x xs) 0 = x" | "at (Signal x xs) (Suc n) = at xs n" text \Inverse to @{term at}\ primcorec from_series :: "(time \ 'a) \ 'a signal" where "from_series f = Signal (f 0) (from_series (f \ Suc))" text \@{typ \'a signal\} is isomorphic to @{typ \time \ 'a\}\ lemma at_from_series: "at (from_series f) = f" proof fix n show "at (from_series f) n = f n" by(induction n arbitrary: f)(subst from_series.code; simp; fail)+ qed lemma at_0: "at xs 0 = head xs" by(cases xs) simp lemma at_Suc: "at xs (Suc n) = at (rest xs) n" by(cases xs) simp lemma from_series_at: "from_series (at xs) = xs" by(coinduction arbitrary: xs)(auto simp add: o_def at_0 at_Suc) text \Define the constant signal by primitive corecursion. It would also work to just use @{term from_series}.\ primcorec constantInt :: "nat \ nat signal" where "constantInt x = Signal x (constantInt x)" text \The selector function would also be primitively corecursive, but we nevertheless define it with @{command corec} because then we can register it as a friend, i.e., it can appear in the context of corecursive calls in later corecursive definitions. \ corec (friend) sel :: "bool signal \ 'a signal \ 'a signal \ 'a signal" where "sel bs xs ys = Signal (if head bs then head xs else head ys) (sel (rest bs) (rest xs) (rest ys))" abbreviation (input) delay :: "'a \ 'a signal \ 'a signal" where "delay \ Signal" \ \The constructor of the codatatype is exactly the delay operator.\ text \ We could define @{text "inc"} corecursively via the equation given below to @command{friend_of_corec}. But since the original theory had defined it via the @{term lift} operation, let's stick to that and establish friendliness separately. \ definition inc :: "nat signal \ nat signal" where "inc as = lift Suc as" friend_of_corec inc where "inc as = Signal (Suc (head as)) (inc (rest as))" subgoal by(cases as)(simp add: inc_def) \ \Prove that the equation indeed describes @{term inc}\ subgoal by transfer_prover \ \The friendliness condition: @{term inc} inspects the argument signal at most at the head before it produces at least one new value.\ done corec nextSig :: "bool signal \ nat signal" where \ \The corecursive call is guarded by the @{term delay} constructor and appears under the friendly operators @{term sig} and @{term inc}.\ "nextSig bs = delay 0 (sel bs (constantInt 0) (inc (nextSig bs)))" definition outputSig :: "bool signal \ nat signal" where "outputSig bS = sel bS (constantInt 0) (inc (nextSig bS))" corec outSig1 :: "bool signal \ nat signal" where "outSig1 bS =sel bS (constantInt 0) (inc (delay 0 (outSig1 bS)))" definition resetCounter :: "bool signal \ nat signal" where "resetCounter b = outputSig b"