{- Copyright (c) 2010, Gregory M. Crosswhite. All rights reserved. -}{-# LANGUAGE Rank2Types #-}moduleTypeLevel.NaturalNumber.Induction(-- * Monadic interfaceInduction(..),inductionMOnLeftFold,inductionMOnRightFold,-- * Pure (non-monadic) interfacededuction,deduction2,induction,transform,inductionOnLeftFold,inductionOnRightFold,)whereimportControl.ApplicativeimportData.Functor.IdentityimportTypeLevel.NaturalNumber-- | The Induction class contains high-level combinators for-- performing monadic operations on inductive structures --- that is,-- datatypes tagged with a natural number.classInductionnwhere-- | The 'deductionM' method provides a high-level combinator for-- folding monadically over an inductive structure; essentially-- this method is the opposite of the 'inductionM' method which-- builds up an inductive structure rather than tearing one down.-- See 'deduction' for a non-monadic version of this function, and-- 'deduction2M' for a version of this function acting on two-- structures simultaneously rather than one.deductionM::Monadm=>α-- ^ the seed data->(fZero->α->mβ)-- ^ the action to perform for the base case->(foralln.f(SuccessorTon)->α->m(fn,α))-- ^ the action to perform for the inductive case->fn-- ^ the structure to fold over->mβ-- ^ the (monadic) result-- | The 'deduction2M' method is the same idea as the 'deductionM'-- method, but it simultaneously folds over two inductive structures-- rather than one.deduction2M::Monadm=>α-- ^ the seed data->(fZero->gZero->α->mβ)-- ^ the action to perform for the base case->(foralln.f(SuccessorTon)->g(SuccessorTon)->α->m(fn,gn,α))-- ^ the action to perform for the inductive case->fn-- ^ the first of the two structures to fold over->gn-- ^ the second of the two structures to fold over->mβ-- ^ the (monadic) result-- | The 'inductionM' method provides a high-level combinator for-- building up an inductive structure monadically starting from-- given seed data; essentially this method is the opposite of-- `deductionM' method which tears down an inductive structure-- rather than building one up. See 'induction' for a non-monadic-- version of this function.inductionM::Monadm=>(α->m(α,fZero))-- ^ the action to perform for the base case->(foralln.α->fn->m(α,f(SuccessorTon)))-- ^ the action to perform for the inductive case->α-- ^ the seed data for the operation->m(α,fn)-- ^ the (monadic) result-- | The 'transformM' method provides a high-level combinator for-- monadically transforming one inductive structure into another.-- See 'transform' for a non-monadic version of this function.transformM::Monadm=>(fZero->m(gZero))-- ^ the action to perform for the base case->(foralln.(fn->m(gn))->f(SuccessorTon)->m(g(SuccessorTon)))-- ^ the action to perform for the inductive case->fn-- ^ the structure to be transformed->m(gn)-- ^ the (monadic) resulting transformed structureinstanceInductionZerowhere-- | Implementation of the Induction class for the base case.deductionMaz_b=zbadeduction2Maz_b1b2=zb1b2ainductionMz_a=zatransformMz_=zinstanceInductionn=>Induction(SuccessorTon)where-- | Implementation of the Induction class for the inductive case.deductionMazdb=dba>>=\(b',a')->deductionMa'zdb'deduction2Mazdb1b2=db1b2a>>=\(b'1,b'2,a')->deduction2Ma'zdb'1b'2inductionMzia=inductionMzia>>=\(a',b')->ia'b'transformMzi=i(transformMzi)-- | The 'deduction' function provides a high-level combinator for-- folding over an inductive structure; essentially this method is the-- opposite of the 'induction' method which builds up an inductive-- structure rather than tearing one down. See 'deductionM' for a-- monadic version of this function, and 'deduction' for a version of-- this function acting on two structures simultaneously rather than-- one.deduction::Inductionn=>α-- ^ the seed data->(fZero->α->β)-- ^ the base case->(foralln.f(SuccessorTon)->α->(fn,α))-- ^ the inductive case->fn-- ^ the structure to fold over->β-- ^ the resultdeductionazdb=runIdentity(deductionMa(\ba->Identity(zba))(\ba->Identity(dba))b)-- | The 'deduction2' function is the same idea as the 'deductionM'-- function, but it simultaneously folds over two inductive structures-- rather than one.deduction2::Inductionn=>α-- ^ the seed data->(fZero->gZero->α->β)-- ^ the base case->(foralln.f(SuccessorTon)->g(SuccessorTon)->α->(fn,gn,α))-- ^ the inductive case->fn-- ^ the first of the two structures to fold over->gn-- ^ the second of the two structures to fold over->β-- ^ the resultdeduction2azdb1b2=runIdentity(deduction2Ma(\b1b2a->Identity(zb1b2a))(\b1b2a->Identity(db1b2a))b1b2)-- | The 'induction' function provides a high-level combinator for-- building up an inductive structure starting from given seed data;-- essentially this method is the opposite of `deduction' method which-- tears down an inductive structure rather than building one up. See-- 'inductionM' for a monadic version of this function.induction::Inductionn=>(a->(a,fZero))->(foralln.a->fn->(a,f(SuccessorTon)))->a->(a,fn)inductionzia=runIdentity(inductionM(Identity.z)(\ab->Identity(iab))a)-- | The 'transform' function provides a high-level combinator for-- transforming one inductive structure into another. See-- 'transformM' for a monadic version of this function.transform::Inductionn=>(fZero->gZero)->(foralln.(fn->gn)->f(SuccessorTon)->g(SuccessorTon))->fn->gntransformzix=runIdentity(transformM(Identity.z)(\f->Identity.i(runIdentity.f))x)-- | The 'inductionOnLeftFold' function is provided for the common-- case where one is building up an inductive structure by performing-- a left fold over a list. A pre-condition of calling this function-- is that the list be the same size as the data structure, i.e. that-- the length of the list be equal to the natural number tagging the-- structure. When this pre-condition is violated, it returns _|_ by-- calling 'error' with a message that the list is either too long or-- too short. See 'inductionMOnLeftFold' for a monadic version of-- this function, and 'inductionOnRightFold' for a version of this-- function that performs a right fold over the list.inductionOnLeftFold::Inductionn=>fZero-- ^ the base case->(foralln.α->fn->f(SuccessorTon))-- ^ the inductive case->[α]-- ^ the list to fold over->fn-- ^ the resultinductionOnLeftFoldzilist=caseleftoversof[]->final_->error"List is too long."where(leftovers,final)=induction(\l->(l,z))(\la->caselof(x:xs)->(xs,ixa)_->error"List is too short.")list-- | This function is the same idea as 'inductionOnLeftFold' function,-- but it performs a right-fold rather than a left-fold over the list.-- See 'inductionMOnRightFold' for a monadic version of this function.inductionOnRightFold::Inductionn=>fZero-- ^ the base case->(foralln.α->fn->f(SuccessorTon))-- ^ the inductive case->[α]-- ^ the list to fold over->fn-- ^ the resultinductionOnRightFoldzi=inductionOnLeftFoldzi.reverse-- | The 'inductionMOnLeftFold' function is provided for the common-- case where one is building up an inductive structure by performing-- a monadic left fold over a list. A pre-condition of calling this-- function is that the list be the same size as the data structure,-- i.e. that the length of the list be equal to the natural number-- tagging the structure. When this pre-condition is violated, it-- returns _|_ by calling 'error' with a message that the list is-- either too long or too short. See 'inductionOnLeftFold' for a-- non-monadic version of this function, and 'inductionMOnRightFold'-- for a version of this function that performs a right fold over the-- list.inductionMOnLeftFold::(Inductionn,Monadm)=>m(fZero)-- ^ the action to perform for the base case->(foralln.α->fn->m(f(SuccessorTon)))-- ^ the action to perform for the inductive case->[α]-- ^ the list to fold over->m(fn)-- ^ the (monadic) resultinductionMOnLeftFoldzilist=do(leftovers,final)<-inductionM(\l->z>>=\a'->return(l,a'))(\la->caselof(x:xs)->ixa>>=\a'->return(xs,a')_->error"List is too short.")listcaseleftoversof[]->returnfinal_->error"List is too long."-- | This function is the same idea as 'inductionMOnLeftFold' function,-- but it performs a right-fold rather than a left-fold over the list.-- See 'inductionOnRightFold' for a non-monadic version of this function.inductionMOnRightFold::(Inductionn,Monadm)=>m(fZero)-- ^ the action to perform for the base case->(foralln.α->fn->m(f(SuccessorTon)))-- ^ the action to perform for the inductive case->[α]-- ^ the list to fold over->m(fn)-- ^ the (monadic) resultinductionMOnRightFoldzi=inductionMOnLeftFoldzi.reverse