ideas 1.5 → 1.6
raw patch · 104 files changed
+2935/−3854 lines, 104 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Ideas.Common.Algebra.Boolean: (<&&>) :: Boolean a => a -> a -> a
- Ideas.Common.Algebra.Boolean: (<||>) :: Boolean a => a -> a -> a
- Ideas.Common.Algebra.Boolean: (><) :: DualMonoid a => a -> a -> a
- Ideas.Common.Algebra.Boolean: And :: a -> And a
- Ideas.Common.Algebra.Boolean: Or :: a -> Or a
- Ideas.Common.Algebra.Boolean: [fromAnd] :: And a -> a
- Ideas.Common.Algebra.Boolean: [fromOr] :: Or a -> a
- Ideas.Common.Algebra.Boolean: ands :: Boolean a => [a] -> a
- Ideas.Common.Algebra.Boolean: class BoolValue a where true = fromBool True false = fromBool False fromBool b = if b then true else false
- Ideas.Common.Algebra.Boolean: class BoolValue a => Boolean a
- Ideas.Common.Algebra.Boolean: class BoolValue a => CoBoolean a
- Ideas.Common.Algebra.Boolean: class MonoidZero a => DualMonoid a
- Ideas.Common.Algebra.Boolean: complement :: Boolean a => a -> a
- Ideas.Common.Algebra.Boolean: conjunctions :: CoBoolean a => a -> [a]
- Ideas.Common.Algebra.Boolean: disjunctions :: CoBoolean a => a -> [a]
- Ideas.Common.Algebra.Boolean: dualCompl :: DualMonoid a => a -> a
- Ideas.Common.Algebra.Boolean: equivalent :: Boolean a => a -> a -> a
- Ideas.Common.Algebra.Boolean: false :: BoolValue a => a
- Ideas.Common.Algebra.Boolean: fromBool :: BoolValue a => Bool -> a
- Ideas.Common.Algebra.Boolean: implies :: Boolean a => a -> a -> a
- Ideas.Common.Algebra.Boolean: instance GHC.Base.Applicative Ideas.Common.Algebra.Boolean.And
- Ideas.Common.Algebra.Boolean: instance GHC.Base.Applicative Ideas.Common.Algebra.Boolean.Or
- Ideas.Common.Algebra.Boolean: instance GHC.Base.Functor Ideas.Common.Algebra.Boolean.And
- Ideas.Common.Algebra.Boolean: instance GHC.Base.Functor Ideas.Common.Algebra.Boolean.Or
- Ideas.Common.Algebra.Boolean: instance GHC.Classes.Eq a => GHC.Classes.Eq (Ideas.Common.Algebra.Boolean.And a)
- Ideas.Common.Algebra.Boolean: instance GHC.Classes.Eq a => GHC.Classes.Eq (Ideas.Common.Algebra.Boolean.Or a)
- Ideas.Common.Algebra.Boolean: instance GHC.Classes.Ord a => GHC.Classes.Ord (Ideas.Common.Algebra.Boolean.And a)
- Ideas.Common.Algebra.Boolean: instance GHC.Classes.Ord a => GHC.Classes.Ord (Ideas.Common.Algebra.Boolean.Or a)
- Ideas.Common.Algebra.Boolean: instance GHC.Show.Show a => GHC.Show.Show (Ideas.Common.Algebra.Boolean.And a)
- Ideas.Common.Algebra.Boolean: instance GHC.Show.Show a => GHC.Show.Show (Ideas.Common.Algebra.Boolean.Or a)
- Ideas.Common.Algebra.Boolean: instance Ideas.Common.Algebra.Boolean.BoolValue GHC.Types.Bool
- Ideas.Common.Algebra.Boolean: instance Ideas.Common.Algebra.Boolean.BoolValue b => Ideas.Common.Algebra.Boolean.BoolValue (a -> b)
- Ideas.Common.Algebra.Boolean: instance Ideas.Common.Algebra.Boolean.Boolean GHC.Types.Bool
- Ideas.Common.Algebra.Boolean: instance Ideas.Common.Algebra.Boolean.Boolean a => GHC.Base.Monoid (Ideas.Common.Algebra.Boolean.And a)
- Ideas.Common.Algebra.Boolean: instance Ideas.Common.Algebra.Boolean.Boolean a => GHC.Base.Monoid (Ideas.Common.Algebra.Boolean.Or a)
- Ideas.Common.Algebra.Boolean: instance Ideas.Common.Algebra.Boolean.Boolean a => Ideas.Common.Algebra.Boolean.DualMonoid (Ideas.Common.Algebra.Boolean.And a)
- Ideas.Common.Algebra.Boolean: instance Ideas.Common.Algebra.Boolean.Boolean a => Ideas.Common.Algebra.Boolean.DualMonoid (Ideas.Common.Algebra.Boolean.Or a)
- Ideas.Common.Algebra.Boolean: instance Ideas.Common.Algebra.Boolean.Boolean a => Ideas.Common.Algebra.Group.MonoidZero (Ideas.Common.Algebra.Boolean.And a)
- Ideas.Common.Algebra.Boolean: instance Ideas.Common.Algebra.Boolean.Boolean a => Ideas.Common.Algebra.Group.MonoidZero (Ideas.Common.Algebra.Boolean.Or a)
- Ideas.Common.Algebra.Boolean: instance Ideas.Common.Algebra.Boolean.Boolean b => Ideas.Common.Algebra.Boolean.Boolean (a -> b)
- Ideas.Common.Algebra.Boolean: instance Ideas.Common.Algebra.Boolean.CoBoolean a => Ideas.Common.Algebra.Group.CoMonoid (Ideas.Common.Algebra.Boolean.And a)
- Ideas.Common.Algebra.Boolean: instance Ideas.Common.Algebra.Boolean.CoBoolean a => Ideas.Common.Algebra.Group.CoMonoid (Ideas.Common.Algebra.Boolean.Or a)
- Ideas.Common.Algebra.Boolean: instance Ideas.Common.Algebra.Boolean.CoBoolean a => Ideas.Common.Algebra.Group.CoMonoidZero (Ideas.Common.Algebra.Boolean.And a)
- Ideas.Common.Algebra.Boolean: instance Ideas.Common.Algebra.Boolean.CoBoolean a => Ideas.Common.Algebra.Group.CoMonoidZero (Ideas.Common.Algebra.Boolean.Or a)
- Ideas.Common.Algebra.Boolean: instance Test.QuickCheck.Arbitrary.Arbitrary a => Test.QuickCheck.Arbitrary.Arbitrary (Ideas.Common.Algebra.Boolean.And a)
- Ideas.Common.Algebra.Boolean: instance Test.QuickCheck.Arbitrary.Arbitrary a => Test.QuickCheck.Arbitrary.Arbitrary (Ideas.Common.Algebra.Boolean.Or a)
- Ideas.Common.Algebra.Boolean: instance Test.QuickCheck.Arbitrary.CoArbitrary a => Test.QuickCheck.Arbitrary.CoArbitrary (Ideas.Common.Algebra.Boolean.And a)
- Ideas.Common.Algebra.Boolean: instance Test.QuickCheck.Arbitrary.CoArbitrary a => Test.QuickCheck.Arbitrary.CoArbitrary (Ideas.Common.Algebra.Boolean.Or a)
- Ideas.Common.Algebra.Boolean: isAnd :: CoBoolean a => a -> Maybe (a, a)
- Ideas.Common.Algebra.Boolean: isComplement :: CoBoolean a => a -> Maybe a
- Ideas.Common.Algebra.Boolean: isFalse :: BoolValue a => a -> Bool
- Ideas.Common.Algebra.Boolean: isOr :: CoBoolean a => a -> Maybe (a, a)
- Ideas.Common.Algebra.Boolean: isTrue :: BoolValue a => a -> Bool
- Ideas.Common.Algebra.Boolean: newtype And a
- Ideas.Common.Algebra.Boolean: newtype Or a
- Ideas.Common.Algebra.Boolean: ors :: Boolean a => [a] -> a
- Ideas.Common.Algebra.Boolean: true :: BoolValue a => a
- Ideas.Common.Algebra.BooleanLaws: absorptionAndLaws :: Boolean a => [Law a]
- Ideas.Common.Algebra.BooleanLaws: absorptionOrLaws :: Boolean a => [Law a]
- Ideas.Common.Algebra.BooleanLaws: andOverOrLaws :: Boolean a => [Law a]
- Ideas.Common.Algebra.BooleanLaws: booleanLaws :: Boolean a => [Law a]
- Ideas.Common.Algebra.BooleanLaws: complementAndLaws :: Boolean a => [Law a]
- Ideas.Common.Algebra.BooleanLaws: complementFalse :: Boolean a => Law a
- Ideas.Common.Algebra.BooleanLaws: complementOrLaws :: Boolean a => [Law a]
- Ideas.Common.Algebra.BooleanLaws: complementTrue :: Boolean a => Law a
- Ideas.Common.Algebra.BooleanLaws: deMorganAnd :: Boolean a => Law a
- Ideas.Common.Algebra.BooleanLaws: deMorganOr :: Boolean a => Law a
- Ideas.Common.Algebra.BooleanLaws: doubleComplement :: Boolean a => Law a
- Ideas.Common.Algebra.BooleanLaws: fromAndLaw :: Law (And a) -> Law a
- Ideas.Common.Algebra.BooleanLaws: fromOrLaw :: Law (Or a) -> Law a
- Ideas.Common.Algebra.BooleanLaws: orOverAndLaws :: Boolean a => [Law a]
- Ideas.Common.Algebra.BooleanLaws: propsBoolean :: [Property]
- Ideas.Common.Algebra.Field: (|*|) :: SemiRing a => a -> a -> a
- Ideas.Common.Algebra.Field: (|+|) :: SemiRing a => a -> a -> a
- Ideas.Common.Algebra.Field: (|-|) :: Ring a => a -> a -> a
- Ideas.Common.Algebra.Field: (|/|) :: Field a => a -> a -> a
- Ideas.Common.Algebra.Field: Additive :: a -> Additive a
- Ideas.Common.Algebra.Field: Multiplicative :: a -> Multiplicative a
- Ideas.Common.Algebra.Field: [fromAdditive] :: Additive a -> a
- Ideas.Common.Algebra.Field: [fromMultiplicative] :: Multiplicative a -> a
- Ideas.Common.Algebra.Field: class CoRing a => CoField a where isDivision _ = Nothing
- Ideas.Common.Algebra.Field: class CoSemiRing a => CoRing a where isMinus _ = Nothing
- Ideas.Common.Algebra.Field: class CoSemiRing a
- Ideas.Common.Algebra.Field: class Ring a => Field a where timesInverse = (one |/|) a |/| b = a |*| timesInverse b
- Ideas.Common.Algebra.Field: class SemiRing a => Ring a where plusInverse = (zero |-|) a |-| b = a |+| plusInverse b
- Ideas.Common.Algebra.Field: class SemiRing a where sum [] = zero sum xs = foldl1 (|+|) xs product [] = one product xs = foldl1 (|*|) xs
- Ideas.Common.Algebra.Field: data SafeNum a
- Ideas.Common.Algebra.Field: instance (GHC.Classes.Eq a, GHC.Real.Fractional a) => GHC.Real.Fractional (Ideas.Common.Algebra.Field.SafeNum a)
- Ideas.Common.Algebra.Field: instance (GHC.Classes.Eq a, GHC.Real.Fractional a) => Ideas.Common.Algebra.Field.Field (Ideas.Common.Algebra.Field.SafeNum a)
- Ideas.Common.Algebra.Field: instance GHC.Base.Applicative Ideas.Common.Algebra.Field.Additive
- Ideas.Common.Algebra.Field: instance GHC.Base.Applicative Ideas.Common.Algebra.Field.Multiplicative
- Ideas.Common.Algebra.Field: instance GHC.Base.Applicative Ideas.Common.Algebra.Field.SafeNum
- Ideas.Common.Algebra.Field: instance GHC.Base.Functor Ideas.Common.Algebra.Field.Additive
- Ideas.Common.Algebra.Field: instance GHC.Base.Functor Ideas.Common.Algebra.Field.Multiplicative
- Ideas.Common.Algebra.Field: instance GHC.Base.Functor Ideas.Common.Algebra.Field.SafeNum
- Ideas.Common.Algebra.Field: instance GHC.Base.Monad Ideas.Common.Algebra.Field.SafeNum
- Ideas.Common.Algebra.Field: instance GHC.Classes.Eq a => GHC.Classes.Eq (Ideas.Common.Algebra.Field.Additive a)
- Ideas.Common.Algebra.Field: instance GHC.Classes.Eq a => GHC.Classes.Eq (Ideas.Common.Algebra.Field.Multiplicative a)
- Ideas.Common.Algebra.Field: instance GHC.Classes.Eq a => GHC.Classes.Eq (Ideas.Common.Algebra.Field.SafeNum a)
- Ideas.Common.Algebra.Field: instance GHC.Classes.Ord a => GHC.Classes.Ord (Ideas.Common.Algebra.Field.Additive a)
- Ideas.Common.Algebra.Field: instance GHC.Classes.Ord a => GHC.Classes.Ord (Ideas.Common.Algebra.Field.Multiplicative a)
- Ideas.Common.Algebra.Field: instance GHC.Classes.Ord a => GHC.Classes.Ord (Ideas.Common.Algebra.Field.SafeNum a)
- Ideas.Common.Algebra.Field: instance GHC.Num.Num a => GHC.Num.Num (Ideas.Common.Algebra.Field.SafeNum a)
- Ideas.Common.Algebra.Field: instance GHC.Num.Num a => Ideas.Common.Algebra.Field.Ring (Ideas.Common.Algebra.Field.SafeNum a)
- Ideas.Common.Algebra.Field: instance GHC.Num.Num a => Ideas.Common.Algebra.Field.SemiRing (Ideas.Common.Algebra.Field.SafeNum a)
- Ideas.Common.Algebra.Field: instance GHC.Show.Show a => GHC.Show.Show (Ideas.Common.Algebra.Field.Additive a)
- Ideas.Common.Algebra.Field: instance GHC.Show.Show a => GHC.Show.Show (Ideas.Common.Algebra.Field.Multiplicative a)
- Ideas.Common.Algebra.Field: instance GHC.Show.Show a => GHC.Show.Show (Ideas.Common.Algebra.Field.SafeNum a)
- Ideas.Common.Algebra.Field: instance Ideas.Common.Algebra.Field.CoField a => Ideas.Common.Algebra.Group.CoGroup (Ideas.Common.Algebra.Field.Multiplicative a)
- Ideas.Common.Algebra.Field: instance Ideas.Common.Algebra.Field.CoRing a => Ideas.Common.Algebra.Group.CoGroup (Ideas.Common.Algebra.Field.Additive a)
- Ideas.Common.Algebra.Field: instance Ideas.Common.Algebra.Field.CoSemiRing a => Ideas.Common.Algebra.Group.CoMonoid (Ideas.Common.Algebra.Field.Additive a)
- Ideas.Common.Algebra.Field: instance Ideas.Common.Algebra.Field.CoSemiRing a => Ideas.Common.Algebra.Group.CoMonoid (Ideas.Common.Algebra.Field.Multiplicative a)
- Ideas.Common.Algebra.Field: instance Ideas.Common.Algebra.Field.CoSemiRing a => Ideas.Common.Algebra.Group.CoMonoidZero (Ideas.Common.Algebra.Field.Multiplicative a)
- Ideas.Common.Algebra.Field: instance Ideas.Common.Algebra.Field.Field a => Ideas.Common.Algebra.Group.Group (Ideas.Common.Algebra.Field.Multiplicative a)
- Ideas.Common.Algebra.Field: instance Ideas.Common.Algebra.Field.Ring a => Ideas.Common.Algebra.Group.Group (Ideas.Common.Algebra.Field.Additive a)
- Ideas.Common.Algebra.Field: instance Ideas.Common.Algebra.Field.SemiRing a => GHC.Base.Monoid (Ideas.Common.Algebra.Field.Additive a)
- Ideas.Common.Algebra.Field: instance Ideas.Common.Algebra.Field.SemiRing a => GHC.Base.Monoid (Ideas.Common.Algebra.Field.Multiplicative a)
- Ideas.Common.Algebra.Field: instance Ideas.Common.Algebra.Field.SemiRing a => Ideas.Common.Algebra.Group.MonoidZero (Ideas.Common.Algebra.Field.Multiplicative a)
- Ideas.Common.Algebra.Field: instance Test.QuickCheck.Arbitrary.Arbitrary a => Test.QuickCheck.Arbitrary.Arbitrary (Ideas.Common.Algebra.Field.Additive a)
- Ideas.Common.Algebra.Field: instance Test.QuickCheck.Arbitrary.Arbitrary a => Test.QuickCheck.Arbitrary.Arbitrary (Ideas.Common.Algebra.Field.Multiplicative a)
- Ideas.Common.Algebra.Field: instance Test.QuickCheck.Arbitrary.Arbitrary a => Test.QuickCheck.Arbitrary.Arbitrary (Ideas.Common.Algebra.Field.SafeNum a)
- Ideas.Common.Algebra.Field: instance Test.QuickCheck.Arbitrary.CoArbitrary a => Test.QuickCheck.Arbitrary.CoArbitrary (Ideas.Common.Algebra.Field.Additive a)
- Ideas.Common.Algebra.Field: instance Test.QuickCheck.Arbitrary.CoArbitrary a => Test.QuickCheck.Arbitrary.CoArbitrary (Ideas.Common.Algebra.Field.Multiplicative a)
- Ideas.Common.Algebra.Field: isDivision :: CoField a => a -> Maybe (a, a)
- Ideas.Common.Algebra.Field: isMinus :: CoRing a => a -> Maybe (a, a)
- Ideas.Common.Algebra.Field: isNegate :: CoRing a => a -> Maybe a
- Ideas.Common.Algebra.Field: isOne :: CoSemiRing a => a -> Bool
- Ideas.Common.Algebra.Field: isPlus :: CoSemiRing a => a -> Maybe (a, a)
- Ideas.Common.Algebra.Field: isRecip :: CoField a => a -> Maybe a
- Ideas.Common.Algebra.Field: isTimes :: CoSemiRing a => a -> Maybe (a, a)
- Ideas.Common.Algebra.Field: isZero :: CoSemiRing a => a -> Bool
- Ideas.Common.Algebra.Field: newtype Additive a
- Ideas.Common.Algebra.Field: newtype Multiplicative a
- Ideas.Common.Algebra.Field: one :: SemiRing a => a
- Ideas.Common.Algebra.Field: plusInverse :: Ring a => a -> a
- Ideas.Common.Algebra.Field: product :: SemiRing a => [a] -> a
- Ideas.Common.Algebra.Field: safeNum :: SafeNum a -> Either String a
- Ideas.Common.Algebra.Field: sum :: SemiRing a => [a] -> a
- Ideas.Common.Algebra.Field: timesInverse :: Field a => a -> a
- Ideas.Common.Algebra.Field: zero :: SemiRing a => a
- Ideas.Common.Algebra.FieldLaws: commutativeRingLaws :: Ring a => [Law a]
- Ideas.Common.Algebra.FieldLaws: distributiveLaws :: SemiRing a => [Law a]
- Ideas.Common.Algebra.FieldLaws: distributiveSubtractionLaws :: Ring a => [Law a]
- Ideas.Common.Algebra.FieldLaws: exchangeInverses :: Field a => Law a
- Ideas.Common.Algebra.FieldLaws: fieldLaws :: Field a => [Law a]
- Ideas.Common.Algebra.FieldLaws: fromAdditiveLaw :: Law (Additive a) -> Law a
- Ideas.Common.Algebra.FieldLaws: fromMultiplicativeLaw :: Law (Multiplicative a) -> Law a
- Ideas.Common.Algebra.FieldLaws: leftDistributive :: SemiRing a => Law a
- Ideas.Common.Algebra.FieldLaws: leftNegateTimes :: Ring a => Law a
- Ideas.Common.Algebra.FieldLaws: negateTimesLaws :: Ring a => [Law a]
- Ideas.Common.Algebra.FieldLaws: propsField :: [Property]
- Ideas.Common.Algebra.FieldLaws: rightDistributive :: SemiRing a => Law a
- Ideas.Common.Algebra.FieldLaws: rightNegateTimes :: Ring a => Law a
- Ideas.Common.Algebra.FieldLaws: ringLaws :: Ring a => [Law a]
- Ideas.Common.Algebra.FieldLaws: semiRingLaws :: SemiRing a => [Law a]
- Ideas.Common.Algebra.Group: (<>) :: Monoid m => m -> m -> m
- Ideas.Common.Algebra.Group: (<>-) :: Group a => a -> a -> a
- Ideas.Common.Algebra.Group: appendInv :: Group a => a -> a -> a
- Ideas.Common.Algebra.Group: associativeList :: CoMonoid a => a -> [a]
- Ideas.Common.Algebra.Group: class CoMonoid a => CoGroup a where isAppendInv = const Nothing
- Ideas.Common.Algebra.Group: class CoMonoid a
- Ideas.Common.Algebra.Group: class CoMonoid a => CoMonoidZero a
- Ideas.Common.Algebra.Group: class Monoid a => Group a where inverse = (mempty <>-) appendInv a b = a <> inverse b
- Ideas.Common.Algebra.Group: class Monoid a
- Ideas.Common.Algebra.Group: class Monoid a => MonoidZero a
- Ideas.Common.Algebra.Group: data WithZero a
- Ideas.Common.Algebra.Group: fromWithZero :: WithZero a -> Maybe a
- Ideas.Common.Algebra.Group: instance Data.Foldable.Foldable Ideas.Common.Algebra.Group.WithZero
- Ideas.Common.Algebra.Group: instance Data.Traversable.Traversable Ideas.Common.Algebra.Group.WithZero
- Ideas.Common.Algebra.Group: instance GHC.Base.Applicative Ideas.Common.Algebra.Group.WithZero
- Ideas.Common.Algebra.Group: instance GHC.Base.Functor Ideas.Common.Algebra.Group.WithZero
- Ideas.Common.Algebra.Group: instance GHC.Base.Monoid a => GHC.Base.Monoid (Ideas.Common.Algebra.Group.WithZero a)
- Ideas.Common.Algebra.Group: instance GHC.Base.Monoid a => Ideas.Common.Algebra.Group.MonoidZero (Ideas.Common.Algebra.Group.WithZero a)
- Ideas.Common.Algebra.Group: instance GHC.Classes.Eq a => GHC.Classes.Eq (Ideas.Common.Algebra.Group.WithZero a)
- Ideas.Common.Algebra.Group: instance GHC.Classes.Ord a => GHC.Classes.Ord (Ideas.Common.Algebra.Group.WithZero a)
- Ideas.Common.Algebra.Group: instance Ideas.Common.Algebra.Group.CoMonoid (Data.Set.Base.Set a)
- Ideas.Common.Algebra.Group: instance Ideas.Common.Algebra.Group.CoMonoid [a]
- Ideas.Common.Algebra.Group: instance Ideas.Common.Algebra.Group.CoMonoid a => Ideas.Common.Algebra.Group.CoMonoid (Ideas.Common.Algebra.Group.WithZero a)
- Ideas.Common.Algebra.Group: instance Ideas.Common.Algebra.Group.CoMonoid a => Ideas.Common.Algebra.Group.CoMonoidZero (Ideas.Common.Algebra.Group.WithZero a)
- Ideas.Common.Algebra.Group: inverse :: Group a => a -> a
- Ideas.Common.Algebra.Group: isAppend :: CoMonoid a => a -> Maybe (a, a)
- Ideas.Common.Algebra.Group: isAppendInv :: CoGroup a => a -> Maybe (a, a)
- Ideas.Common.Algebra.Group: isEmpty :: CoMonoid a => a -> Bool
- Ideas.Common.Algebra.Group: isInverse :: CoGroup a => a -> Maybe a
- Ideas.Common.Algebra.Group: isMonoidZero :: CoMonoidZero a => a -> Bool
- Ideas.Common.Algebra.Group: mappend :: Monoid a => a -> a -> a
- Ideas.Common.Algebra.Group: mconcat :: Monoid a => [a] -> a
- Ideas.Common.Algebra.Group: mempty :: Monoid a => a
- Ideas.Common.Algebra.Group: mzero :: MonoidZero a => a
- Ideas.Common.Algebra.GroupLaws: abelianGroupLaws :: Group a => [Law a]
- Ideas.Common.Algebra.GroupLaws: appendInverseLaws :: Group a => [Law a]
- Ideas.Common.Algebra.GroupLaws: associative :: Monoid a => Law a
- Ideas.Common.Algebra.GroupLaws: associativeFor :: (a -> a -> a) -> Law a
- Ideas.Common.Algebra.GroupLaws: commutative :: Monoid a => Law a
- Ideas.Common.Algebra.GroupLaws: commutativeFor :: (a -> a -> a) -> Law a
- Ideas.Common.Algebra.GroupLaws: commutativeMonoidLaws :: Monoid a => [Law a]
- Ideas.Common.Algebra.GroupLaws: doubleInverse :: Group a => Law a
- Ideas.Common.Algebra.GroupLaws: groupLaws :: Group a => [Law a]
- Ideas.Common.Algebra.GroupLaws: idempotent :: Monoid a => Law a
- Ideas.Common.Algebra.GroupLaws: idempotentFor :: (a -> a -> a) -> Law a
- Ideas.Common.Algebra.GroupLaws: identityLaws :: Monoid a => [Law a]
- Ideas.Common.Algebra.GroupLaws: inverseDistr :: Group a => Law a
- Ideas.Common.Algebra.GroupLaws: inverseDistrFlipped :: Group a => Law a
- Ideas.Common.Algebra.GroupLaws: inverseIdentity :: Group a => Law a
- Ideas.Common.Algebra.GroupLaws: inverseLaws :: Group a => [Law a]
- Ideas.Common.Algebra.GroupLaws: leftDistributiveFor :: (a -> a -> a) -> (a -> a -> a) -> Law a
- Ideas.Common.Algebra.GroupLaws: leftIdentity :: Monoid a => Law a
- Ideas.Common.Algebra.GroupLaws: leftInverse :: Group a => Law a
- Ideas.Common.Algebra.GroupLaws: leftZero :: MonoidZero a => Law a
- Ideas.Common.Algebra.GroupLaws: monoidLaws :: Monoid a => [Law a]
- Ideas.Common.Algebra.GroupLaws: monoidZeroLaws :: MonoidZero a => [Law a]
- Ideas.Common.Algebra.GroupLaws: rightDistributiveFor :: (a -> a -> a) -> (a -> a -> a) -> Law a
- Ideas.Common.Algebra.GroupLaws: rightIdentity :: Monoid a => Law a
- Ideas.Common.Algebra.GroupLaws: rightInverse :: Group a => Law a
- Ideas.Common.Algebra.GroupLaws: rightZero :: MonoidZero a => Law a
- Ideas.Common.Algebra.GroupLaws: zeroLaws :: MonoidZero a => [Law a]
- Ideas.Common.Algebra.Law: (:==:) :: a -> a -> LawSpec a
- Ideas.Common.Algebra.Law: data Law a
- Ideas.Common.Algebra.Law: data LawSpec a
- Ideas.Common.Algebra.Law: instance (GHC.Show.Show a, GHC.Classes.Eq a, Test.QuickCheck.Arbitrary.Arbitrary a) => Test.QuickCheck.Property.Testable (Ideas.Common.Algebra.Law.Law a)
- Ideas.Common.Algebra.Law: instance (Test.QuickCheck.Arbitrary.Arbitrary a, Ideas.Common.Rewriting.Term.IsTerm a, GHC.Show.Show a, Ideas.Common.Rewriting.RewriteRule.Different a) => Ideas.Common.Rewriting.RewriteRule.RuleBuilder (Ideas.Common.Algebra.Law.LawSpec a) a
- Ideas.Common.Algebra.Law: instance GHC.Show.Show (Ideas.Common.Algebra.Law.Law a)
- Ideas.Common.Algebra.Law: instance Ideas.Common.Algebra.Law.LawBuilder (Ideas.Common.Algebra.Law.Law a) a
- Ideas.Common.Algebra.Law: instance Ideas.Common.Algebra.Law.LawBuilder (Ideas.Common.Algebra.Law.LawSpec a) a
- Ideas.Common.Algebra.Law: instance Ideas.Common.Algebra.Law.LawBuilder b a => Ideas.Common.Algebra.Law.LawBuilder (a -> b) a
- Ideas.Common.Algebra.Law: law :: LawBuilder l a => String -> l -> Law a
- Ideas.Common.Algebra.Law: lawAbs :: (Different b, Arbitrary b, Show b) => (b -> LawSpec a) -> LawSpec a
- Ideas.Common.Algebra.Law: mapLaw :: (b -> a) -> (a -> b) -> Law a -> Law b
- Ideas.Common.Algebra.Law: propertyLaw :: (Arbitrary a, Show a, Testable b) => (a -> a -> b) -> Law a -> Property
- Ideas.Common.Algebra.Law: rewriteLaw :: (Different a, IsTerm a, Arbitrary a, Show a) => Law a -> RewriteRule a
- Ideas.Common.Algebra.SmartGroup: (.&&.) :: (Boolean a, CoBoolean a) => a -> a -> a
- Ideas.Common.Algebra.SmartGroup: (.*.) :: (CoField a, Field a) => a -> a -> a
- Ideas.Common.Algebra.SmartGroup: (.+.) :: (CoField a, Field a) => a -> a -> a
- Ideas.Common.Algebra.SmartGroup: (.-.) :: (CoField a, Field a) => a -> a -> a
- Ideas.Common.Algebra.SmartGroup: (./.) :: (CoField a, Field a) => a -> a -> a
- Ideas.Common.Algebra.SmartGroup: (.||.) :: (Boolean a, CoBoolean a) => a -> a -> a
- Ideas.Common.Algebra.SmartGroup: Smart :: a -> Smart a
- Ideas.Common.Algebra.SmartGroup: SmartField :: a -> SmartField a
- Ideas.Common.Algebra.SmartGroup: SmartGroup :: a -> SmartGroup a
- Ideas.Common.Algebra.SmartGroup: SmartZero :: a -> SmartZero a
- Ideas.Common.Algebra.SmartGroup: [fromSmartField] :: SmartField a -> a
- Ideas.Common.Algebra.SmartGroup: [fromSmartGroup] :: SmartGroup a -> a
- Ideas.Common.Algebra.SmartGroup: [fromSmartZero] :: SmartZero a -> a
- Ideas.Common.Algebra.SmartGroup: [fromSmart] :: Smart a -> a
- Ideas.Common.Algebra.SmartGroup: instance (Ideas.Common.Algebra.Boolean.Boolean a, Ideas.Common.Algebra.Boolean.CoBoolean a) => Ideas.Common.Algebra.Boolean.Boolean (Ideas.Common.Algebra.SmartGroup.Smart a)
- Ideas.Common.Algebra.SmartGroup: instance (Ideas.Common.Algebra.Field.CoField a, Ideas.Common.Algebra.Field.Field a) => Ideas.Common.Algebra.Field.Field (Ideas.Common.Algebra.SmartGroup.SmartField a)
- Ideas.Common.Algebra.SmartGroup: instance (Ideas.Common.Algebra.Field.CoField a, Ideas.Common.Algebra.Field.Field a) => Ideas.Common.Algebra.Field.Ring (Ideas.Common.Algebra.SmartGroup.SmartField a)
- Ideas.Common.Algebra.SmartGroup: instance (Ideas.Common.Algebra.Field.CoField a, Ideas.Common.Algebra.Field.Field a) => Ideas.Common.Algebra.Field.SemiRing (Ideas.Common.Algebra.SmartGroup.SmartField a)
- Ideas.Common.Algebra.SmartGroup: instance (Ideas.Common.Algebra.Group.CoGroup a, Ideas.Common.Algebra.Group.Group a) => GHC.Base.Monoid (Ideas.Common.Algebra.SmartGroup.SmartGroup a)
- Ideas.Common.Algebra.SmartGroup: instance (Ideas.Common.Algebra.Group.CoGroup a, Ideas.Common.Algebra.Group.Group a) => Ideas.Common.Algebra.Group.Group (Ideas.Common.Algebra.SmartGroup.SmartGroup a)
- Ideas.Common.Algebra.SmartGroup: instance (Ideas.Common.Algebra.Group.CoGroup a, Ideas.Common.Algebra.Group.MonoidZero a, Ideas.Common.Algebra.Group.Group a) => Ideas.Common.Algebra.Group.MonoidZero (Ideas.Common.Algebra.SmartGroup.SmartGroup a)
- Ideas.Common.Algebra.SmartGroup: instance (Ideas.Common.Algebra.Group.CoMonoid a, GHC.Base.Monoid a) => GHC.Base.Monoid (Ideas.Common.Algebra.SmartGroup.Smart a)
- Ideas.Common.Algebra.SmartGroup: instance (Ideas.Common.Algebra.Group.CoMonoid a, Ideas.Common.Algebra.Group.MonoidZero a) => Ideas.Common.Algebra.Group.MonoidZero (Ideas.Common.Algebra.SmartGroup.Smart a)
- Ideas.Common.Algebra.SmartGroup: instance (Ideas.Common.Algebra.Group.CoMonoidZero a, Ideas.Common.Algebra.Group.MonoidZero a) => GHC.Base.Monoid (Ideas.Common.Algebra.SmartGroup.SmartZero a)
- Ideas.Common.Algebra.SmartGroup: instance (Ideas.Common.Algebra.Group.CoMonoidZero a, Ideas.Common.Algebra.Group.MonoidZero a) => Ideas.Common.Algebra.Group.MonoidZero (Ideas.Common.Algebra.SmartGroup.SmartZero a)
- Ideas.Common.Algebra.SmartGroup: instance GHC.Base.Applicative Ideas.Common.Algebra.SmartGroup.Smart
- Ideas.Common.Algebra.SmartGroup: instance GHC.Base.Applicative Ideas.Common.Algebra.SmartGroup.SmartField
- Ideas.Common.Algebra.SmartGroup: instance GHC.Base.Applicative Ideas.Common.Algebra.SmartGroup.SmartGroup
- Ideas.Common.Algebra.SmartGroup: instance GHC.Base.Applicative Ideas.Common.Algebra.SmartGroup.SmartZero
- Ideas.Common.Algebra.SmartGroup: instance GHC.Base.Functor Ideas.Common.Algebra.SmartGroup.Smart
- Ideas.Common.Algebra.SmartGroup: instance GHC.Base.Functor Ideas.Common.Algebra.SmartGroup.SmartField
- Ideas.Common.Algebra.SmartGroup: instance GHC.Base.Functor Ideas.Common.Algebra.SmartGroup.SmartGroup
- Ideas.Common.Algebra.SmartGroup: instance GHC.Base.Functor Ideas.Common.Algebra.SmartGroup.SmartZero
- Ideas.Common.Algebra.SmartGroup: instance GHC.Classes.Eq a => GHC.Classes.Eq (Ideas.Common.Algebra.SmartGroup.Smart a)
- Ideas.Common.Algebra.SmartGroup: instance GHC.Classes.Eq a => GHC.Classes.Eq (Ideas.Common.Algebra.SmartGroup.SmartGroup a)
- Ideas.Common.Algebra.SmartGroup: instance GHC.Classes.Eq a => GHC.Classes.Eq (Ideas.Common.Algebra.SmartGroup.SmartZero a)
- Ideas.Common.Algebra.SmartGroup: instance GHC.Classes.Ord a => GHC.Classes.Ord (Ideas.Common.Algebra.SmartGroup.Smart a)
- Ideas.Common.Algebra.SmartGroup: instance GHC.Classes.Ord a => GHC.Classes.Ord (Ideas.Common.Algebra.SmartGroup.SmartGroup a)
- Ideas.Common.Algebra.SmartGroup: instance GHC.Classes.Ord a => GHC.Classes.Ord (Ideas.Common.Algebra.SmartGroup.SmartZero a)
- Ideas.Common.Algebra.SmartGroup: instance GHC.Show.Show a => GHC.Show.Show (Ideas.Common.Algebra.SmartGroup.Smart a)
- Ideas.Common.Algebra.SmartGroup: instance GHC.Show.Show a => GHC.Show.Show (Ideas.Common.Algebra.SmartGroup.SmartGroup a)
- Ideas.Common.Algebra.SmartGroup: instance GHC.Show.Show a => GHC.Show.Show (Ideas.Common.Algebra.SmartGroup.SmartZero a)
- Ideas.Common.Algebra.SmartGroup: instance Ideas.Common.Algebra.Boolean.BoolValue a => Ideas.Common.Algebra.Boolean.BoolValue (Ideas.Common.Algebra.SmartGroup.Smart a)
- Ideas.Common.Algebra.SmartGroup: instance Ideas.Common.Algebra.Field.CoField a => Ideas.Common.Algebra.Field.CoField (Ideas.Common.Algebra.SmartGroup.SmartField a)
- Ideas.Common.Algebra.SmartGroup: instance Ideas.Common.Algebra.Field.CoRing a => Ideas.Common.Algebra.Field.CoRing (Ideas.Common.Algebra.SmartGroup.SmartField a)
- Ideas.Common.Algebra.SmartGroup: instance Ideas.Common.Algebra.Field.CoSemiRing a => Ideas.Common.Algebra.Field.CoSemiRing (Ideas.Common.Algebra.SmartGroup.SmartField a)
- Ideas.Common.Algebra.SmartGroup: instance Ideas.Common.Algebra.Group.CoGroup a => Ideas.Common.Algebra.Group.CoGroup (Ideas.Common.Algebra.SmartGroup.SmartGroup a)
- Ideas.Common.Algebra.SmartGroup: instance Ideas.Common.Algebra.Group.CoMonoid a => Ideas.Common.Algebra.Group.CoMonoid (Ideas.Common.Algebra.SmartGroup.Smart a)
- Ideas.Common.Algebra.SmartGroup: instance Ideas.Common.Algebra.Group.CoMonoid a => Ideas.Common.Algebra.Group.CoMonoid (Ideas.Common.Algebra.SmartGroup.SmartGroup a)
- Ideas.Common.Algebra.SmartGroup: instance Ideas.Common.Algebra.Group.CoMonoid a => Ideas.Common.Algebra.Group.CoMonoid (Ideas.Common.Algebra.SmartGroup.SmartZero a)
- Ideas.Common.Algebra.SmartGroup: instance Ideas.Common.Algebra.Group.CoMonoidZero a => Ideas.Common.Algebra.Group.CoMonoidZero (Ideas.Common.Algebra.SmartGroup.Smart a)
- Ideas.Common.Algebra.SmartGroup: instance Ideas.Common.Algebra.Group.CoMonoidZero a => Ideas.Common.Algebra.Group.CoMonoidZero (Ideas.Common.Algebra.SmartGroup.SmartGroup a)
- Ideas.Common.Algebra.SmartGroup: instance Ideas.Common.Algebra.Group.CoMonoidZero a => Ideas.Common.Algebra.Group.CoMonoidZero (Ideas.Common.Algebra.SmartGroup.SmartZero a)
- Ideas.Common.Algebra.SmartGroup: neg :: (CoField a, Field a) => a -> a
- Ideas.Common.Algebra.SmartGroup: newtype Smart a
- Ideas.Common.Algebra.SmartGroup: newtype SmartField a
- Ideas.Common.Algebra.SmartGroup: newtype SmartGroup a
- Ideas.Common.Algebra.SmartGroup: newtype SmartZero a
- Ideas.Common.CyclicTree: data CyclicTree a b
- Ideas.Common.CyclicTree: data CyclicTreeAlg a b t
- Ideas.Common.CyclicTree: emptyAlg :: CyclicTreeAlg a b t
- Ideas.Common.CyclicTree: fLabel :: CyclicTreeAlg a b t -> Id -> t -> t
- Ideas.Common.CyclicTree: fLeaf :: CyclicTreeAlg a b t -> b -> t
- Ideas.Common.CyclicTree: fNode :: CyclicTreeAlg a b t -> a -> [t] -> t
- Ideas.Common.CyclicTree: fRec :: CyclicTreeAlg a b t -> Int -> t -> t
- Ideas.Common.CyclicTree: fVar :: CyclicTreeAlg a b t -> Int -> t
- Ideas.Common.CyclicTree: fold :: CyclicTreeAlg a b t -> CyclicTree a b -> t
- Ideas.Common.CyclicTree: foldUnwind :: CyclicTreeAlg a b t -> CyclicTree a b -> t
- Ideas.Common.CyclicTree: instance (GHC.Show.Show a, GHC.Show.Show b) => GHC.Show.Show (Ideas.Common.CyclicTree.CyclicTree a b)
- Ideas.Common.CyclicTree: instance (Test.QuickCheck.Arbitrary.Arbitrary a, Test.QuickCheck.Arbitrary.Arbitrary b) => Test.QuickCheck.Arbitrary.Arbitrary (Ideas.Common.CyclicTree.CyclicTree a b)
- Ideas.Common.CyclicTree: instance Data.Foldable.Foldable (Ideas.Common.CyclicTree.CyclicTree d)
- Ideas.Common.CyclicTree: instance Data.Traversable.Traversable (Ideas.Common.CyclicTree.CyclicTree d)
- Ideas.Common.CyclicTree: instance GHC.Base.Applicative (Ideas.Common.CyclicTree.CyclicTree d)
- Ideas.Common.CyclicTree: instance GHC.Base.Functor (Ideas.Common.CyclicTree.CyclicTree d)
- Ideas.Common.CyclicTree: instance GHC.Base.Monad (Ideas.Common.CyclicTree.CyclicTree d)
- Ideas.Common.CyclicTree: instance Ideas.Common.Classes.BiFunctor Ideas.Common.CyclicTree.CyclicTree
- Ideas.Common.CyclicTree: instance Ideas.Common.Classes.Fix (Ideas.Common.CyclicTree.CyclicTree a b)
- Ideas.Common.CyclicTree: isLabel :: CyclicTree a b -> Maybe (Id, CyclicTree a b)
- Ideas.Common.CyclicTree: isLeaf :: CyclicTree a b -> Maybe b
- Ideas.Common.CyclicTree: isNode :: CyclicTree a b -> Maybe (a, [CyclicTree a b])
- Ideas.Common.CyclicTree: label :: IsId n => n -> CyclicTree a b -> CyclicTree a b
- Ideas.Common.CyclicTree: leaf :: b -> CyclicTree a b
- Ideas.Common.CyclicTree: monoidAlg :: Monoid m => CyclicTreeAlg a b m
- Ideas.Common.CyclicTree: node :: a -> [CyclicTree a b] -> CyclicTree a b
- Ideas.Common.CyclicTree: node0 :: a -> CyclicTree a b
- Ideas.Common.CyclicTree: node1 :: a -> CyclicTree a b -> CyclicTree a b
- Ideas.Common.CyclicTree: node2 :: a -> CyclicTree a b -> CyclicTree a b -> CyclicTree a b
- Ideas.Common.CyclicTree: replaceLabel :: (Id -> CyclicTree a b -> CyclicTree a b) -> CyclicTree a b -> CyclicTree a b
- Ideas.Common.CyclicTree: replaceLeaf :: (b -> CyclicTree a c) -> CyclicTree a b -> CyclicTree a c
- Ideas.Common.CyclicTree: replaceNode :: (a -> [CyclicTree a b] -> CyclicTree a b) -> CyclicTree a b -> CyclicTree a b
- Ideas.Common.CyclicTree: shrinkTree :: CyclicTree a b -> [CyclicTree a b]
- Ideas.Common.Environment: instance Ideas.Common.Environment.Reference Ideas.Common.Utils.ShowString
- Ideas.Common.Exercise: instance Data.Data.Data Ideas.Common.Exercise.Difficulty
- Ideas.Common.Id: instance Data.Data.Data Ideas.Common.Id.Id
- Ideas.Common.Predicate: instance Ideas.Common.Algebra.Boolean.BoolValue (Ideas.Common.Predicate.Predicate a)
- Ideas.Common.Predicate: instance Ideas.Common.Algebra.Boolean.Boolean (Ideas.Common.Predicate.Predicate a)
- Ideas.Common.Rewriting.Term: instance Ideas.Common.Rewriting.Term.IsTerm Ideas.Common.Utils.ShowString
- Ideas.Common.Rule.Abstract: addRecognizerEnvMonad :: (a -> a -> EnvMonad ()) -> Rule a -> Rule a
- Ideas.Common.Rule.Abstract: isRecognizer :: Rule a -> Bool
- Ideas.Common.Rule.EnvironmentMonad: (:=) :: Ref a -> a -> EnvMonad ()
- Ideas.Common.Rule.EnvironmentMonad: (:?) :: Ref a -> a -> EnvMonad a
- Ideas.Common.Rule.EnvironmentMonad: (:~) :: Ref a -> (a -> a) -> EnvMonad ()
- Ideas.Common.Rule.EnvironmentMonad: data EnvMonad a
- Ideas.Common.Rule.EnvironmentMonad: envMonadFunctionRefs :: (a -> EnvMonad b) -> [Some Ref]
- Ideas.Common.Rule.EnvironmentMonad: envMonadRefs :: EnvMonad a -> [Some Ref]
- Ideas.Common.Rule.EnvironmentMonad: evalEnvMonad :: EnvMonad a -> Environment -> [a]
- Ideas.Common.Rule.EnvironmentMonad: execEnvMonad :: EnvMonad a -> Environment -> [Environment]
- Ideas.Common.Rule.EnvironmentMonad: getRef :: Typeable a => Ref a -> EnvMonad a
- Ideas.Common.Rule.EnvironmentMonad: instance GHC.Base.Alternative Ideas.Common.Rule.EnvironmentMonad.EnvMonad
- Ideas.Common.Rule.EnvironmentMonad: instance GHC.Base.Applicative Ideas.Common.Rule.EnvironmentMonad.EnvMonad
- Ideas.Common.Rule.EnvironmentMonad: instance GHC.Base.Functor Ideas.Common.Rule.EnvironmentMonad.EnvMonad
- Ideas.Common.Rule.EnvironmentMonad: instance GHC.Base.Monad Ideas.Common.Rule.EnvironmentMonad.EnvMonad
- Ideas.Common.Rule.EnvironmentMonad: instance GHC.Base.MonadPlus Ideas.Common.Rule.EnvironmentMonad.EnvMonad
- Ideas.Common.Rule.EnvironmentMonad: runEnvMonad :: EnvMonad a -> Environment -> [(a, Environment)]
- Ideas.Common.Rule.EnvironmentMonad: updateRefs :: MonadPlus m => [EnvMonad a] -> Environment -> m Environment
- Ideas.Common.Rule.Parameter: supplyContextParameters :: ParamTrans b a -> (a -> EnvMonad b) -> Transformation (Context a)
- Ideas.Common.Rule.Recognizer: makeRecognizerEnvMonad :: (a -> a -> EnvMonad ()) -> Recognizer a
- Ideas.Common.Rule.Transformation: instance Control.Arrow.ArrowApply Ideas.Common.Rule.Transformation.Trans
- Ideas.Common.Rule.Transformation: instance Ideas.Common.Rule.Transformation.MakeTrans Ideas.Common.Rule.EnvironmentMonad.EnvMonad
- Ideas.Common.Rule.Transformation: isZeroTrans :: Trans a b -> Bool
- Ideas.Common.Rule.Transformation: makeTransLiftContext :: MakeTrans f => (a -> f a) -> Transformation (Context a)
- Ideas.Common.Rule.Transformation: makeTransLiftContext_ :: MakeTrans f => (a -> f ()) -> Transformation (Context a)
- Ideas.Common.Rule.Transformation: transEnvMonad :: (a -> EnvMonad b) -> Trans a b
- Ideas.Common.Rule.Transformation: transRef :: Typeable a => Ref a -> Trans a a
- Ideas.Common.Strategy.StrategyTree: data Binary a
- Ideas.Common.Strategy.StrategyTree: data Nary a
- Ideas.Common.Strategy.StrategyTree: data Nullary a
- Ideas.Common.Strategy.StrategyTree: data Unary a
- Ideas.Common.Strategy.Symbol: atomicClose :: AtomicSymbol a => a
- Ideas.Common.Strategy.Symbol: atomicOpen :: AtomicSymbol a => a
- Ideas.Common.Utils: ShowString :: String -> ShowString
- Ideas.Common.Utils: Some :: (f a) -> Some f
- Ideas.Common.Utils: [fromShowString] :: ShowString -> String
- Ideas.Common.Utils: allsame :: Eq a => [a] -> Bool
- Ideas.Common.Utils: cartesian :: [a] -> [b] -> [(a, b)]
- Ideas.Common.Utils: changeAt :: Monad m => Int -> (a -> a) -> [a] -> m [a]
- Ideas.Common.Utils: data ShowString
- Ideas.Common.Utils: data Some f
- Ideas.Common.Utils: distinct :: Eq a => [a] -> Bool
- Ideas.Common.Utils: elementAt :: Monad m => Int -> [a] -> m a
- Ideas.Common.Utils: findIndexM :: Monad m => (a -> Bool) -> [a] -> m Int
- Ideas.Common.Utils: fixpoint :: Eq a => (a -> a) -> a -> a
- Ideas.Common.Utils: fst3 :: (a, b, c) -> a
- Ideas.Common.Utils: headM :: Monad m => [a] -> m a
- Ideas.Common.Utils: instance GHC.Classes.Eq Ideas.Common.Utils.ShowString
- Ideas.Common.Utils: instance GHC.Classes.Ord Ideas.Common.Utils.ShowString
- Ideas.Common.Utils: instance GHC.Read.Read Ideas.Common.Utils.ShowString
- Ideas.Common.Utils: instance GHC.Show.Show Ideas.Common.Utils.ShowString
- Ideas.Common.Utils: isSubsetOf :: Eq a => [a] -> [a] -> Bool
- Ideas.Common.Utils: list :: b -> ([a] -> b) -> [a] -> b
- Ideas.Common.Utils: readInt :: String -> Maybe Int
- Ideas.Common.Utils: readM :: (Monad m, Read a) => String -> m a
- Ideas.Common.Utils: replaceAt :: Monad m => Int -> a -> [a] -> m [a]
- Ideas.Common.Utils: snd3 :: (a, b, c) -> b
- Ideas.Common.Utils: splitAtElem :: Eq a => a -> [a] -> Maybe ([a], [a])
- Ideas.Common.Utils: splitsWithElem :: Eq a => a -> [a] -> [[a]]
- Ideas.Common.Utils: subsets :: [a] -> [[a]]
- Ideas.Common.Utils: thd3 :: (a, b, c) -> c
- Ideas.Common.Utils: timedSeconds :: Int -> IO a -> IO a
- Ideas.Common.Utils.QuickCheck: arbGen :: Arbitrary b => (b -> a) -> ArbGen a
- Ideas.Common.Utils.QuickCheck: binaryGen :: (a -> a -> a) -> ArbGen a
- Ideas.Common.Utils.QuickCheck: binaryGens :: [a -> a -> a] -> ArbGen a
- Ideas.Common.Utils.QuickCheck: changeFrequency :: Rational -> ArbGen a -> ArbGen a
- Ideas.Common.Utils.QuickCheck: common :: ArbGen a -> ArbGen a
- Ideas.Common.Utils.QuickCheck: constGen :: a -> ArbGen a
- Ideas.Common.Utils.QuickCheck: constGens :: [a] -> ArbGen a
- Ideas.Common.Utils.QuickCheck: data ArbGen a
- Ideas.Common.Utils.QuickCheck: generator :: ArbGen a -> Gen a
- Ideas.Common.Utils.QuickCheck: generators :: [ArbGen a] -> Gen a
- Ideas.Common.Utils.QuickCheck: instance GHC.Base.Monoid (Ideas.Common.Utils.QuickCheck.ArbGen a)
- Ideas.Common.Utils.QuickCheck: rare :: ArbGen a -> ArbGen a
- Ideas.Common.Utils.QuickCheck: toArbGen :: Gen a -> ArbGen a
- Ideas.Common.Utils.QuickCheck: unaryArbGen :: Arbitrary b => (b -> a -> a) -> ArbGen a
- Ideas.Common.Utils.QuickCheck: unaryGen :: (a -> a) -> ArbGen a
- Ideas.Common.Utils.QuickCheck: unaryGens :: [a -> a] -> ArbGen a
- Ideas.Common.Utils.QuickCheck: uncommon :: ArbGen a -> ArbGen a
- Ideas.Common.Utils.StringRef: data StringRef
- Ideas.Common.Utils.StringRef: instance Data.Data.Data Ideas.Common.Utils.StringRef.StringRef
- Ideas.Common.Utils.StringRef: instance GHC.Classes.Eq Ideas.Common.Utils.StringRef.StringRef
- Ideas.Common.Utils.StringRef: instance GHC.Classes.Ord Ideas.Common.Utils.StringRef.StringRef
- Ideas.Common.Utils.StringRef: stringRef :: String -> StringRef
- Ideas.Common.Utils.StringRef: tableStatus :: IO String
- Ideas.Common.Utils.StringRef: toString :: StringRef -> String
- Ideas.Common.Utils.TestSuite: allMessages :: Result -> [(String, Message)]
- Ideas.Common.Utils.TestSuite: assertEquals :: (Eq a, Show a) => String -> a -> a -> TestSuite
- Ideas.Common.Utils.TestSuite: assertIO :: String -> IO Bool -> TestSuite
- Ideas.Common.Utils.TestSuite: assertMessage :: String -> Bool -> String -> TestSuite
- Ideas.Common.Utils.TestSuite: assertMessageIO :: String -> IO Message -> TestSuite
- Ideas.Common.Utils.TestSuite: assertNull :: Show a => String -> [a] -> TestSuite
- Ideas.Common.Utils.TestSuite: assertTrue :: String -> Bool -> TestSuite
- Ideas.Common.Utils.TestSuite: class HasRating a
- Ideas.Common.Utils.TestSuite: class HasStatus a
- Ideas.Common.Utils.TestSuite: data Message
- Ideas.Common.Utils.TestSuite: data Rating
- Ideas.Common.Utils.TestSuite: data Result
- Ideas.Common.Utils.TestSuite: data Status
- Ideas.Common.Utils.TestSuite: data TestSuite
- Ideas.Common.Utils.TestSuite: findSubResult :: String -> Result -> Maybe Result
- Ideas.Common.Utils.TestSuite: getStatus :: HasStatus a => a -> Status
- Ideas.Common.Utils.TestSuite: instance GHC.Base.Monoid Ideas.Common.Utils.TestSuite.Message
- Ideas.Common.Utils.TestSuite: instance GHC.Base.Monoid Ideas.Common.Utils.TestSuite.Rating
- Ideas.Common.Utils.TestSuite: instance GHC.Base.Monoid Ideas.Common.Utils.TestSuite.Result
- Ideas.Common.Utils.TestSuite: instance GHC.Base.Monoid Ideas.Common.Utils.TestSuite.Status
- Ideas.Common.Utils.TestSuite: instance GHC.Base.Monoid Ideas.Common.Utils.TestSuite.TestSuite
- Ideas.Common.Utils.TestSuite: instance GHC.Classes.Eq Ideas.Common.Utils.TestSuite.Message
- Ideas.Common.Utils.TestSuite: instance GHC.Classes.Eq Ideas.Common.Utils.TestSuite.Rating
- Ideas.Common.Utils.TestSuite: instance GHC.Classes.Eq Ideas.Common.Utils.TestSuite.Status
- Ideas.Common.Utils.TestSuite: instance GHC.Classes.Ord Ideas.Common.Utils.TestSuite.Rating
- Ideas.Common.Utils.TestSuite: instance GHC.Classes.Ord Ideas.Common.Utils.TestSuite.Status
- Ideas.Common.Utils.TestSuite: instance GHC.Show.Show Ideas.Common.Utils.TestSuite.Message
- Ideas.Common.Utils.TestSuite: instance GHC.Show.Show Ideas.Common.Utils.TestSuite.Result
- Ideas.Common.Utils.TestSuite: instance Ideas.Common.Utils.TestSuite.HasRating Ideas.Common.Utils.TestSuite.Message
- Ideas.Common.Utils.TestSuite: instance Ideas.Common.Utils.TestSuite.HasRating Ideas.Common.Utils.TestSuite.Rating
- Ideas.Common.Utils.TestSuite: instance Ideas.Common.Utils.TestSuite.HasRating Ideas.Common.Utils.TestSuite.Result
- Ideas.Common.Utils.TestSuite: instance Ideas.Common.Utils.TestSuite.HasStatus Ideas.Common.Utils.TestSuite.Message
- Ideas.Common.Utils.TestSuite: instance Ideas.Common.Utils.TestSuite.HasStatus Ideas.Common.Utils.TestSuite.Result
- Ideas.Common.Utils.TestSuite: isError :: HasStatus a => a -> Bool
- Ideas.Common.Utils.TestSuite: isOk :: HasStatus a => a -> Bool
- Ideas.Common.Utils.TestSuite: isWarning :: HasStatus a => a -> Bool
- Ideas.Common.Utils.TestSuite: justOneSuite :: Result -> Maybe (String, Result)
- Ideas.Common.Utils.TestSuite: makeSummary :: Result -> String
- Ideas.Common.Utils.TestSuite: message :: String -> Message
- Ideas.Common.Utils.TestSuite: messageLines :: Message -> [String]
- Ideas.Common.Utils.TestSuite: nrOfErrors :: Result -> Int
- Ideas.Common.Utils.TestSuite: nrOfTests :: Result -> Int
- Ideas.Common.Utils.TestSuite: nrOfWarnings :: Result -> Int
- Ideas.Common.Utils.TestSuite: onlyWarnings :: TestSuite -> TestSuite
- Ideas.Common.Utils.TestSuite: printSummary :: Result -> IO ()
- Ideas.Common.Utils.TestSuite: rate :: HasRating a => Int -> a -> a
- Ideas.Common.Utils.TestSuite: rateOnError :: Int -> TestSuite -> TestSuite
- Ideas.Common.Utils.TestSuite: rating :: HasRating a => a -> Maybe Int
- Ideas.Common.Utils.TestSuite: runTestSuite :: Bool -> TestSuite -> IO ()
- Ideas.Common.Utils.TestSuite: runTestSuiteResult :: Bool -> TestSuite -> IO Result
- Ideas.Common.Utils.TestSuite: subResults :: Result -> [(String, Result)]
- Ideas.Common.Utils.TestSuite: suite :: String -> [TestSuite] -> TestSuite
- Ideas.Common.Utils.TestSuite: timeInterval :: Result -> Double
- Ideas.Common.Utils.TestSuite: topMessages :: Result -> [(String, Message)]
- Ideas.Common.Utils.TestSuite: useProperty :: Testable prop => String -> prop -> TestSuite
- Ideas.Common.Utils.TestSuite: usePropertyWith :: Testable prop => String -> Args -> prop -> TestSuite
- Ideas.Common.Utils.TestSuite: warning :: String -> Message
- Ideas.Common.Utils.Uniplate: (|*) :: Type (to -> from) to -> to -> Type from to
- Ideas.Common.Utils.Uniplate: (|-) :: Type (item -> from) to -> item -> Type from to
- Ideas.Common.Utils.Uniplate: (||*) :: Type ([to] -> from) to -> [to] -> Type from to
- Ideas.Common.Utils.Uniplate: children :: Uniplate on => on -> [on]
- Ideas.Common.Utils.Uniplate: class Uniplate on
- Ideas.Common.Utils.Uniplate: contexts :: Uniplate on => on -> [(on, on -> on)]
- Ideas.Common.Utils.Uniplate: descend :: Uniplate on => (on -> on) -> on -> on
- Ideas.Common.Utils.Uniplate: descendM :: Uniplate on => forall (m :: * -> *). Monad m => (on -> m on) -> on -> m on
- Ideas.Common.Utils.Uniplate: holes :: Uniplate on => on -> [(on, on -> on)]
- Ideas.Common.Utils.Uniplate: para :: Uniplate on => (on -> [r] -> r) -> on -> r
- Ideas.Common.Utils.Uniplate: plate :: from -> Type from to
- Ideas.Common.Utils.Uniplate: rewrite :: Uniplate on => (on -> Maybe on) -> on -> on
- Ideas.Common.Utils.Uniplate: rewriteM :: (Monad m, Uniplate on) => (on -> m (Maybe on)) -> on -> m on
- Ideas.Common.Utils.Uniplate: transform :: Uniplate on => (on -> on) -> on -> on
- Ideas.Common.Utils.Uniplate: transformM :: (Monad m, Uniplate on) => (on -> m on) -> on -> m on
- Ideas.Common.Utils.Uniplate: uniplate :: Uniplate on => on -> (Str on, Str on -> on)
- Ideas.Common.Utils.Uniplate: universe :: Uniplate on => on -> [on]
- Ideas.Common.View: ViewPackage :: (String -> Maybe a) -> View a b -> ViewPackage
- Ideas.Encoding.Encoder: data Options a
- Ideas.Encoding.Encoder: jsonTermView :: InJSON a => View Term a
- Ideas.Encoding.Encoder: makeOptions :: DomainReasoner -> Request -> IO (Some Options)
- Ideas.Encoding.Encoder: simpleOptions :: Exercise a -> Options a
- Ideas.Encoding.EncoderHTML: htmlEncoderAt :: Int -> DomainReasoner -> TypedEncoder a HTMLPage
- Ideas.Encoding.LinkManager: (</>) :: String -> FilePath -> FilePath
- Ideas.Encoding.LinkManager: [isStatic] :: LinkManager -> Bool
- Ideas.Encoding.LinkManager: dynamicLinks :: String -> LinkManager
- Ideas.Encoding.LinkManager: linksUp :: Int -> LinkManager -> LinkManager
- Ideas.Encoding.LinkManager: pathLevel :: FilePath -> Int
- Ideas.Encoding.LinkManager: staticLinks :: LinkManager
- Ideas.Main.BlackBoxTests: blackBoxTests :: DomainReasoner -> String -> IO TestSuite
- Ideas.Main.Default: Some :: (f a) -> Some f
- Ideas.Main.Default: data Some f
- Ideas.Main.Documentation: makeDocumentation :: DomainReasoner -> String -> IO ()
- Ideas.Main.Logging: Record :: String -> String -> String -> String -> String -> String -> String -> String -> String -> String -> Time -> Diff -> String -> String -> String -> String -> String -> String -> String -> String -> Record
- Ideas.Main.Logging: [binary] :: Record -> String
- Ideas.Main.Logging: [dataformat] :: Record -> String
- Ideas.Main.Logging: [encoding] :: Record -> String
- Ideas.Main.Logging: [errormsg] :: Record -> String
- Ideas.Main.Logging: [exerciseid] :: Record -> String
- Ideas.Main.Logging: [input] :: Record -> String
- Ideas.Main.Logging: [ipaddress] :: Record -> String
- Ideas.Main.Logging: [output] :: Record -> String
- Ideas.Main.Logging: [requestinfo] :: Record -> String
- Ideas.Main.Logging: [responsetime] :: Record -> Diff
- Ideas.Main.Logging: [ruleid] :: Record -> String
- Ideas.Main.Logging: [script] :: Record -> String
- Ideas.Main.Logging: [service] :: Record -> String
- Ideas.Main.Logging: [serviceinfo] :: Record -> String
- Ideas.Main.Logging: [sessionid] :: Record -> String
- Ideas.Main.Logging: [source] :: Record -> String
- Ideas.Main.Logging: [taskid] :: Record -> String
- Ideas.Main.Logging: [time] :: Record -> Time
- Ideas.Main.Logging: [userid] :: Record -> String
- Ideas.Main.Logging: [version] :: Record -> String
- Ideas.Main.Logging: addRequest :: Request -> Record -> Record
- Ideas.Main.Logging: addState :: State a -> Record -> Record
- Ideas.Main.Logging: changeLog :: LogRef -> (Record -> Record) -> IO ()
- Ideas.Main.Logging: data LogRef
- Ideas.Main.Logging: data Record
- Ideas.Main.Logging: instance GHC.Show.Show Ideas.Main.Logging.Record
- Ideas.Main.Logging: logEnabled :: Bool
- Ideas.Main.Logging: logRecord :: Schema -> LogRef -> IO ()
- Ideas.Main.Logging: newLogRef :: IO LogRef
- Ideas.Main.Logging: noLogRef :: LogRef
- Ideas.Main.Logging: printLog :: LogRef -> IO ()
- Ideas.Main.Options: AnalyzeScript :: FilePath -> Flag
- Ideas.Main.Options: Help :: Flag
- Ideas.Main.Options: InputFile :: String -> Flag
- Ideas.Main.Options: MakePages :: FilePath -> Flag
- Ideas.Main.Options: MakeScriptFor :: String -> Flag
- Ideas.Main.Options: PrintLog :: Flag
- Ideas.Main.Options: Test :: FilePath -> Flag
- Ideas.Main.Options: Version :: Flag
- Ideas.Main.Options: data Flag
- Ideas.Main.Options: fullVersion :: String
- Ideas.Main.Options: getFlags :: IO [Flag]
- Ideas.Main.Options: helpText :: String
- Ideas.Main.Options: instance GHC.Classes.Eq Ideas.Main.Options.Flag
- Ideas.Main.Options: shortVersion :: String
- Ideas.Main.Options: versionText :: String
- Ideas.Service.Request: EncCompact :: Encoding
- Ideas.Service.Request: EncHTML :: Encoding
- Ideas.Service.Request: EncJSON :: Encoding
- Ideas.Service.Request: EncOpenMath :: Encoding
- Ideas.Service.Request: EncPretty :: Encoding
- Ideas.Service.Request: EncString :: Encoding
- Ideas.Service.Request: JSON :: DataFormat
- Ideas.Service.Request: NoLogging :: Schema
- Ideas.Service.Request: Request :: Maybe Id -> Maybe Id -> Maybe String -> Maybe String -> Maybe String -> Maybe String -> Maybe Schema -> Maybe Int -> DataFormat -> [Encoding] -> Request
- Ideas.Service.Request: V1 :: Schema
- Ideas.Service.Request: V2 :: Schema
- Ideas.Service.Request: XML :: DataFormat
- Ideas.Service.Request: [cgiBinary] :: Request -> Maybe String
- Ideas.Service.Request: [dataformat] :: Request -> DataFormat
- Ideas.Service.Request: [encoding] :: Request -> [Encoding]
- Ideas.Service.Request: [exerciseId] :: Request -> Maybe Id
- Ideas.Service.Request: [feedbackScript] :: Request -> Maybe String
- Ideas.Service.Request: [logSchema] :: Request -> Maybe Schema
- Ideas.Service.Request: [randomSeed] :: Request -> Maybe Int
- Ideas.Service.Request: [requestInfo] :: Request -> Maybe String
- Ideas.Service.Request: [serviceId] :: Request -> Maybe Id
- Ideas.Service.Request: [source] :: Request -> Maybe String
- Ideas.Service.Request: compactOutput :: Request -> Bool
- Ideas.Service.Request: data DataFormat
- Ideas.Service.Request: data Encoding
- Ideas.Service.Request: data Request
- Ideas.Service.Request: data Schema
- Ideas.Service.Request: discoverDataFormat :: Monad m => String -> m DataFormat
- Ideas.Service.Request: emptyRequest :: Request
- Ideas.Service.Request: getSchema :: Request -> Schema
- Ideas.Service.Request: htmlOutput :: Request -> Bool
- Ideas.Service.Request: instance GHC.Classes.Eq Ideas.Service.Request.Encoding
- Ideas.Service.Request: instance GHC.Classes.Eq Ideas.Service.Request.Schema
- Ideas.Service.Request: instance GHC.Show.Show Ideas.Service.Request.DataFormat
- Ideas.Service.Request: instance GHC.Show.Show Ideas.Service.Request.Encoding
- Ideas.Service.Request: instance GHC.Show.Show Ideas.Service.Request.Schema
- Ideas.Service.Request: readEncoding :: Monad m => String -> m [Encoding]
- Ideas.Service.Request: readSchema :: Monad m => String -> m Schema
- Ideas.Service.Request: useJSONTerm :: Request -> Bool
- Ideas.Service.Request: useLogging :: Request -> Bool
- Ideas.Service.Request: useOpenMath :: Request -> Bool
- Ideas.Service.Types: (:->) :: TypeRep f t1 -> TypeRep f t2 -> TypeRep f (t1 -> t2)
- Ideas.Service.Types: (:::) :: t -> f t -> TypedValue f
- Ideas.Service.Types: (:|:) :: TypeRep f t1 -> TypeRep f t2 -> TypeRep f (Either t1 t2)
- Ideas.Service.Types: Bool :: Const a Bool
- Ideas.Service.Types: Const :: f t -> TypeRep f t
- Ideas.Service.Types: Context :: Const a (Context a)
- Ideas.Service.Types: Environment :: Const a Environment
- Ideas.Service.Types: Exercise :: Const a (Exercise a)
- Ideas.Service.Types: IO :: TypeRep f t -> TypeRep f (IO t)
- Ideas.Service.Types: Id :: Const a Id
- Ideas.Service.Types: Int :: Const a Int
- Ideas.Service.Types: Iso :: Isomorphism t1 t2 -> TypeRep f t1 -> TypeRep f t2
- Ideas.Service.Types: List :: TypeRep f t -> TypeRep f [t]
- Ideas.Service.Types: Location :: Const a Location
- Ideas.Service.Types: Pair :: TypeRep f t1 -> TypeRep f t2 -> TypeRep f (t1, t2)
- Ideas.Service.Types: QCGen :: Const a QCGen
- Ideas.Service.Types: Result :: Const a Result
- Ideas.Service.Types: Rule :: Const a (Rule (Context a))
- Ideas.Service.Types: Script :: Const a Script
- Ideas.Service.Types: Service :: Const a Service
- Ideas.Service.Types: SomeExercise :: Const a (Some Exercise)
- Ideas.Service.Types: State :: Const a (State a)
- Ideas.Service.Types: StratCfg :: Const a StrategyCfg
- Ideas.Service.Types: Strategy :: Const a (Strategy (Context a))
- Ideas.Service.Types: String :: Const a String
- Ideas.Service.Types: Tag :: String -> TypeRep f t1 -> TypeRep f t1
- Ideas.Service.Types: Term :: Const a Term
- Ideas.Service.Types: Text :: Const a Text
- Ideas.Service.Types: Unit :: TypeRep f ()
- Ideas.Text.Parsing: (*>) :: Applicative f => forall a b. f a -> f b -> f b
- Ideas.Text.Parsing: (<$) :: Functor f => forall a b. a -> f b -> f a
- Ideas.Text.Parsing: (<$>) :: Functor f => (a -> b) -> f a -> f b
- Ideas.Text.Parsing: (<*) :: Applicative f => forall a b. f a -> f b -> f a
- Ideas.Text.Parsing: (<**>) :: Applicative f => f a -> f (a -> b) -> f b
- Ideas.Text.Parsing: (<*>) :: Applicative f => forall a b. f (a -> b) -> f a -> f b
- Ideas.Text.Parsing: (<..>) :: Char -> Char -> Parser Char
- Ideas.Text.Parsing: NotClosed :: SourcePos -> Char -> UnbalancedError
- Ideas.Text.Parsing: NotOpened :: SourcePos -> Char -> UnbalancedError
- Ideas.Text.Parsing: balanced :: [(Char, Char)] -> String -> Maybe UnbalancedError
- Ideas.Text.Parsing: complete :: Parser a -> Parser a
- Ideas.Text.Parsing: data UnbalancedError
- Ideas.Text.Parsing: float :: Parser Double
- Ideas.Text.Parsing: instance GHC.Show.Show Ideas.Text.Parsing.UnbalancedError
- Ideas.Text.Parsing: naturalOrFloat :: Parser (Either Integer Double)
- Ideas.Text.Parsing: parseSimple :: Parser a -> String -> Either String a
- Ideas.Text.Parsing: ranges :: [(Char, Char)] -> Parser Char
- Ideas.Text.Parsing: skip :: Parser a -> Parser ()
- Ideas.Text.Parsing: stopOn :: [String] -> Parser String
- Ideas.Text.XML.Document: data Parameter
+ Ideas.Common.Classes: (<&&>) :: Boolean a => a -> a -> a
+ Ideas.Common.Classes: (<||>) :: Boolean a => a -> a -> a
+ Ideas.Common.Classes: ands :: Boolean a => [a] -> a
+ Ideas.Common.Classes: class BoolValue a where true = fromBool True false = fromBool False fromBool b = if b then true else false
+ Ideas.Common.Classes: class BoolValue a => Boolean a
+ Ideas.Common.Classes: complement :: Boolean a => a -> a
+ Ideas.Common.Classes: equivalent :: Boolean a => a -> a -> a
+ Ideas.Common.Classes: false :: BoolValue a => a
+ Ideas.Common.Classes: fromBool :: BoolValue a => Bool -> a
+ Ideas.Common.Classes: implies :: Boolean a => a -> a -> a
+ Ideas.Common.Classes: instance Ideas.Common.Classes.BoolValue GHC.Types.Bool
+ Ideas.Common.Classes: instance Ideas.Common.Classes.BoolValue b => Ideas.Common.Classes.BoolValue (a -> b)
+ Ideas.Common.Classes: instance Ideas.Common.Classes.Boolean GHC.Types.Bool
+ Ideas.Common.Classes: instance Ideas.Common.Classes.Boolean b => Ideas.Common.Classes.Boolean (a -> b)
+ Ideas.Common.Classes: isFalse :: BoolValue a => a -> Bool
+ Ideas.Common.Classes: isTrue :: BoolValue a => a -> Bool
+ Ideas.Common.Classes: ors :: Boolean a => [a] -> a
+ Ideas.Common.Classes: true :: BoolValue a => a
+ Ideas.Common.Environment: instance Ideas.Common.Environment.Reference Ideas.Utils.Prelude.ShowString
+ Ideas.Common.Environment: instance Ideas.Utils.Typeable.HasTypeable Ideas.Common.Environment.Ref
+ Ideas.Common.Environment: mapRef :: Typeable b => Isomorphism a b -> Ref a -> Ref b
+ Ideas.Common.Exercise: getPropertyF :: (IsId n, Typeable f) => n -> Exercise a -> Maybe (f a)
+ Ideas.Common.Exercise: instance Ideas.Utils.Typeable.HasTypeable Ideas.Common.Exercise.Exercise
+ Ideas.Common.Exercise: setPropertyF :: (IsId n, Typeable f) => n -> f a -> Exercise a -> Exercise a
+ Ideas.Common.Id: infixr 8 #
+ Ideas.Common.Library: Some :: (f a) -> Some f
+ Ideas.Common.Library: data Some f
+ Ideas.Common.Predicate: instance Ideas.Common.Classes.BoolValue (Ideas.Common.Predicate.Predicate a)
+ Ideas.Common.Predicate: instance Ideas.Common.Classes.Boolean (Ideas.Common.Predicate.Predicate a)
+ Ideas.Common.Rewriting.Substitution: infix 6 @+@
+ Ideas.Common.Rewriting.Substitution: infixr 5 |->
+ Ideas.Common.Rewriting.Substitution: infixr 6 @@
+ Ideas.Common.Rewriting.Term: falseSymbol :: Symbol
+ Ideas.Common.Rewriting.Term: fromTermList :: (IsTerm a, MonadPlus m) => Term -> m [a]
+ Ideas.Common.Rewriting.Term: instance (Ideas.Common.Rewriting.Term.IsTerm a, GHC.Classes.Ord a) => Ideas.Common.Rewriting.Term.IsTerm (Data.Set.Base.Set a)
+ Ideas.Common.Rewriting.Term: instance (Ideas.Common.Rewriting.Term.IsTerm a, Ideas.Common.Rewriting.Term.IsTerm b, GHC.Classes.Ord a) => Ideas.Common.Rewriting.Term.IsTerm (Data.Map.Base.Map a b)
+ Ideas.Common.Rewriting.Term: instance Ideas.Common.Rewriting.Term.IsTerm GHC.Types.Bool
+ Ideas.Common.Rewriting.Term: instance Ideas.Common.Rewriting.Term.IsTerm Ideas.Utils.Prelude.ShowString
+ Ideas.Common.Rewriting.Term: instance Ideas.Common.Rewriting.Term.IsTerm a => Ideas.Common.Rewriting.Term.IsTerm (GHC.Base.Maybe a)
+ Ideas.Common.Rewriting.Term: nothingSymbol :: Symbol
+ Ideas.Common.Rewriting.Term: toTermList :: IsTerm a => [a] -> Term
+ Ideas.Common.Rewriting.Term: trueSymbol :: Symbol
+ Ideas.Common.Rule.Parameter: input :: Ref i -> Trans (i, a) b -> Trans a b
+ Ideas.Common.Rule.Parameter: inputWith :: Trans a i -> Trans (i, a) b -> Trans a b
+ Ideas.Common.Rule.Parameter: output :: Ref o -> Trans a (b, o) -> Trans a b
+ Ideas.Common.Rule.Parameter: outputOnly :: Ref o -> Trans a o -> Trans a a
+ Ideas.Common.Rule.Parameter: outputOnly2 :: Ref o1 -> Ref o2 -> Trans a (o1, o2) -> Trans a a
+ Ideas.Common.Rule.Parameter: outputOnly3 :: Ref o1 -> Ref o2 -> Ref o3 -> Trans a (o1, o2, o3) -> Trans a a
+ Ideas.Common.Rule.Parameter: outputOnlyWith :: Trans o x -> Trans a o -> Trans a a
+ Ideas.Common.Rule.Parameter: outputWith :: Trans o x -> Trans a (b, o) -> Trans a b
+ Ideas.Common.Rule.Parameter: readRef2 :: Ref a -> Ref b -> Trans x (a, b)
+ Ideas.Common.Rule.Parameter: readRef3 :: Ref a -> Ref b -> Ref c -> Trans x (a, b, c)
+ Ideas.Common.Rule.Parameter: transInput1 :: Ref i -> (i -> a -> Maybe b) -> Trans a b
+ Ideas.Common.Rule.Parameter: transInput2 :: Ref i1 -> Ref i2 -> (i1 -> i2 -> a -> Maybe b) -> Trans a b
+ Ideas.Common.Rule.Parameter: transInput3 :: Ref i1 -> Ref i2 -> Ref i3 -> (i1 -> i2 -> i3 -> a -> Maybe b) -> Trans a b
+ Ideas.Common.Rule.Parameter: transInputWith :: MakeTrans f => Trans a i -> (i -> a -> f b) -> Trans a b
+ Ideas.Common.Rule.Parameter: transRef :: Ref a -> Trans a a
+ Ideas.Common.Rule.Parameter: writeRef2 :: Ref a -> Ref b -> Trans (a, b) (a, b)
+ Ideas.Common.Rule.Parameter: writeRef2_ :: Ref a -> Ref b -> Trans (a, b) ()
+ Ideas.Common.Rule.Parameter: writeRef3 :: Ref a -> Ref b -> Ref c -> Trans (a, b, c) (a, b, c)
+ Ideas.Common.Rule.Parameter: writeRef3_ :: Ref a -> Ref b -> Ref c -> Trans (a, b, c) ()
+ Ideas.Common.Rule.Transformation: instance GHC.Base.Alternative (Ideas.Common.Rule.Transformation.Trans a)
+ Ideas.Common.Rule.Transformation: instance GHC.Base.Applicative (Ideas.Common.Rule.Transformation.Trans a)
+ Ideas.Common.Rule.Transformation: instance GHC.Base.Functor (Ideas.Common.Rule.Transformation.Trans a)
+ Ideas.Common.Rule.Transformation: readRef :: Ref a -> Trans x a
+ Ideas.Common.Rule.Transformation: readRefDefault :: a -> Ref a -> Trans x a
+ Ideas.Common.Rule.Transformation: readRefMaybe :: Ref a -> Trans x (Maybe a)
+ Ideas.Common.Rule.Transformation: transGuard :: (a -> Bool) -> Trans a a
+ Ideas.Common.Rule.Transformation: writeRef :: Ref a -> Trans a a
+ Ideas.Common.Rule.Transformation: writeRefMaybe :: Ref a -> Trans (Maybe a) ()
+ Ideas.Common.Rule.Transformation: writeRef_ :: Ref a -> Trans a ()
+ Ideas.Common.Strategy: dynamic :: (IsId n, IsStrategy f, IsTerm a) => n -> (a -> f a) -> Strategy a
+ Ideas.Common.Strategy: infixr 2 .@.
+ Ideas.Common.Strategy: infixr 3 .|.
+ Ideas.Common.Strategy: infixr 4 ./.
+ Ideas.Common.Strategy: infixr 5 !~>
+ Ideas.Common.Strategy.Abstract: instance Ideas.Common.Strategy.Abstract.IsStrategy Ideas.Common.Strategy.StrategyTree.Dynamic
+ Ideas.Common.Strategy.Choice: infixr 5 |->
+ Ideas.Common.Strategy.Combinators: dynamic :: (IsId n, IsStrategy f, IsTerm a) => n -> (a -> f a) -> Strategy a
+ Ideas.Common.Strategy.Combinators: infixr 2 .@.
+ Ideas.Common.Strategy.Combinators: infixr 3 .|.
+ Ideas.Common.Strategy.Combinators: infixr 4 |>
+ Ideas.Common.Strategy.Combinators: infixr 5 !~>
+ Ideas.Common.Strategy.CyclicTree: data CyclicTree a b
+ Ideas.Common.Strategy.CyclicTree: data CyclicTreeAlg a b t
+ Ideas.Common.Strategy.CyclicTree: emptyAlg :: CyclicTreeAlg a b t
+ Ideas.Common.Strategy.CyclicTree: fLabel :: CyclicTreeAlg a b t -> Id -> t -> t
+ Ideas.Common.Strategy.CyclicTree: fLeaf :: CyclicTreeAlg a b t -> b -> t
+ Ideas.Common.Strategy.CyclicTree: fNode :: CyclicTreeAlg a b t -> a -> [t] -> t
+ Ideas.Common.Strategy.CyclicTree: fRec :: CyclicTreeAlg a b t -> Int -> t -> t
+ Ideas.Common.Strategy.CyclicTree: fVar :: CyclicTreeAlg a b t -> Int -> t
+ Ideas.Common.Strategy.CyclicTree: fold :: CyclicTreeAlg a b t -> CyclicTree a b -> t
+ Ideas.Common.Strategy.CyclicTree: foldUnwind :: CyclicTreeAlg a b t -> CyclicTree a b -> t
+ Ideas.Common.Strategy.CyclicTree: instance (GHC.Show.Show a, GHC.Show.Show b) => GHC.Show.Show (Ideas.Common.Strategy.CyclicTree.CyclicTree a b)
+ Ideas.Common.Strategy.CyclicTree: instance (Test.QuickCheck.Arbitrary.Arbitrary a, Test.QuickCheck.Arbitrary.Arbitrary b) => Test.QuickCheck.Arbitrary.Arbitrary (Ideas.Common.Strategy.CyclicTree.CyclicTree a b)
+ Ideas.Common.Strategy.CyclicTree: instance Data.Foldable.Foldable (Ideas.Common.Strategy.CyclicTree.CyclicTree d)
+ Ideas.Common.Strategy.CyclicTree: instance Data.Traversable.Traversable (Ideas.Common.Strategy.CyclicTree.CyclicTree d)
+ Ideas.Common.Strategy.CyclicTree: instance GHC.Base.Applicative (Ideas.Common.Strategy.CyclicTree.CyclicTree d)
+ Ideas.Common.Strategy.CyclicTree: instance GHC.Base.Functor (Ideas.Common.Strategy.CyclicTree.CyclicTree d)
+ Ideas.Common.Strategy.CyclicTree: instance GHC.Base.Monad (Ideas.Common.Strategy.CyclicTree.CyclicTree d)
+ Ideas.Common.Strategy.CyclicTree: instance Ideas.Common.Classes.BiFunctor Ideas.Common.Strategy.CyclicTree.CyclicTree
+ Ideas.Common.Strategy.CyclicTree: instance Ideas.Common.Classes.Fix (Ideas.Common.Strategy.CyclicTree.CyclicTree a b)
+ Ideas.Common.Strategy.CyclicTree: isLabel :: CyclicTree a b -> Maybe (Id, CyclicTree a b)
+ Ideas.Common.Strategy.CyclicTree: isLeaf :: CyclicTree a b -> Maybe b
+ Ideas.Common.Strategy.CyclicTree: isNode :: CyclicTree a b -> Maybe (a, [CyclicTree a b])
+ Ideas.Common.Strategy.CyclicTree: label :: IsId n => n -> CyclicTree a b -> CyclicTree a b
+ Ideas.Common.Strategy.CyclicTree: leaf :: b -> CyclicTree a b
+ Ideas.Common.Strategy.CyclicTree: monoidAlg :: Monoid m => CyclicTreeAlg a b m
+ Ideas.Common.Strategy.CyclicTree: node :: a -> [CyclicTree a b] -> CyclicTree a b
+ Ideas.Common.Strategy.CyclicTree: node0 :: a -> CyclicTree a b
+ Ideas.Common.Strategy.CyclicTree: node1 :: a -> CyclicTree a b -> CyclicTree a b
+ Ideas.Common.Strategy.CyclicTree: node2 :: a -> CyclicTree a b -> CyclicTree a b -> CyclicTree a b
+ Ideas.Common.Strategy.CyclicTree: replaceLabel :: (Id -> CyclicTree a b -> CyclicTree a b) -> CyclicTree a b -> CyclicTree a b
+ Ideas.Common.Strategy.CyclicTree: replaceLeaf :: (b -> CyclicTree a c) -> CyclicTree a b -> CyclicTree a c
+ Ideas.Common.Strategy.CyclicTree: replaceNode :: (a -> [CyclicTree a b] -> CyclicTree a b) -> CyclicTree a b -> CyclicTree a b
+ Ideas.Common.Strategy.CyclicTree: shrinkTree :: CyclicTree a b -> [CyclicTree a b]
+ Ideas.Common.Strategy.Legacy: infixr 2 <@>
+ Ideas.Common.Strategy.Legacy: infixr 3 <|>
+ Ideas.Common.Strategy.Legacy: infixr 4 >|>
+ Ideas.Common.Strategy.Legacy: infixr 5 <*>
+ Ideas.Common.Strategy.Prefix: instance GHC.Classes.Eq Ideas.Common.Strategy.Prefix.PathItem
+ Ideas.Common.Strategy.Prefix: instance GHC.Read.Read Ideas.Common.Strategy.Prefix.PathItem
+ Ideas.Common.Strategy.Prefix: instance GHC.Show.Show Ideas.Common.Strategy.Prefix.PathItem
+ Ideas.Common.Strategy.Sequence: type family Elem s;
+ Ideas.Common.Strategy.Sequence: }
+ Ideas.Common.Strategy.StrategyTree: LeafDyn :: (Dynamic a) -> Leaf a
+ Ideas.Common.Strategy.StrategyTree: LeafRule :: (Rule a) -> Leaf a
+ Ideas.Common.Strategy.StrategyTree: data Dynamic a
+ Ideas.Common.Strategy.StrategyTree: data Leaf a
+ Ideas.Common.Strategy.StrategyTree: dynamicFromTerm :: Dynamic a -> Term -> Maybe (StrategyTree a)
+ Ideas.Common.Strategy.StrategyTree: dynamicToTerm :: Dynamic a -> a -> Maybe Term
+ Ideas.Common.Strategy.StrategyTree: dynamicTree :: Dynamic a -> a -> Maybe (StrategyTree a)
+ Ideas.Common.Strategy.StrategyTree: infix 1 .=.
+ Ideas.Common.Strategy.StrategyTree: instance GHC.Classes.Eq (Ideas.Common.Strategy.StrategyTree.Leaf a)
+ Ideas.Common.Strategy.StrategyTree: instance GHC.Show.Show (Ideas.Common.Strategy.StrategyTree.Leaf a)
+ Ideas.Common.Strategy.StrategyTree: instance Ideas.Common.Classes.Apply Ideas.Common.Strategy.StrategyTree.Dynamic
+ Ideas.Common.Strategy.StrategyTree: instance Ideas.Common.Classes.Apply Ideas.Common.Strategy.StrategyTree.Leaf
+ Ideas.Common.Strategy.StrategyTree: instance Ideas.Common.Classes.Minor (Ideas.Common.Strategy.StrategyTree.Leaf a)
+ Ideas.Common.Strategy.StrategyTree: instance Ideas.Common.Id.HasId (Ideas.Common.Strategy.StrategyTree.Dynamic a)
+ Ideas.Common.Strategy.StrategyTree: instance Ideas.Common.Id.HasId (Ideas.Common.Strategy.StrategyTree.Leaf a)
+ Ideas.Common.Strategy.StrategyTree: instance Ideas.Common.Strategy.Symbol.AtomicSymbol (Ideas.Common.Strategy.StrategyTree.Leaf a)
+ Ideas.Common.Strategy.StrategyTree: instance Ideas.Common.Strategy.Symbol.LabelSymbol (Ideas.Common.Strategy.StrategyTree.Leaf a)
+ Ideas.Common.Strategy.StrategyTree: instance Ideas.Common.View.LiftView Ideas.Common.Strategy.StrategyTree.Dynamic
+ Ideas.Common.Strategy.StrategyTree: instance Ideas.Common.View.LiftView Ideas.Common.Strategy.StrategyTree.Leaf
+ Ideas.Common.Strategy.StrategyTree: makeDynamic :: (IsId n, IsTerm a) => n -> (a -> StrategyTree a) -> Dynamic a
+ Ideas.Common.Strategy.StrategyTree: mapRulesInTree :: (Rule a -> Rule a) -> StrategyTree a -> StrategyTree a
+ Ideas.Common.Strategy.StrategyTree: newtype Binary a
+ Ideas.Common.Strategy.StrategyTree: newtype Nary a
+ Ideas.Common.Strategy.StrategyTree: newtype Nullary a
+ Ideas.Common.Strategy.StrategyTree: newtype Unary a
+ Ideas.Common.Strategy.StrategyTree: treeToProcess :: StrategyTree a -> Process (Leaf a)
+ Ideas.Common.Strategy.Symbol: atomicOpen, atomicClose :: AtomicSymbol a => a
+ Ideas.Common.Traversal.Utils: infixr 0 >|<
+ Ideas.Common.Traversal.Utils: infixr 1 >=>
+ Ideas.Common.Traversal.Utils: type family Unfocus a;
+ Ideas.Common.Traversal.Utils: }
+ Ideas.Common.View: [ViewPackage] :: (Show a, Show b, Eq a) => (String -> Maybe a) -> View a b -> ViewPackage
+ Ideas.Common.View: infixr 1 <<<
+ Ideas.Encoding.Encoder: addJSONView :: View JSON a -> Exercise a -> Exercise a
+ Ideas.Encoding.Encoder: fromExercise :: Converter f => (Exercise a -> t) -> f a s t
+ Ideas.Encoding.Encoder: getBaseUrl :: Converter f => f a s String
+ Ideas.Encoding.Encoder: hasJSONView :: Exercise a -> Maybe (View JSON a)
+ Ideas.Encoding.Encoder: hasLatexEncoding :: Exercise a -> Bool
+ Ideas.Encoding.Encoder: infixr 5 <?>
+ Ideas.Encoding.Encoder: jsonEncoding :: InJSON a => Exercise a -> Exercise a
+ Ideas.Encoding.Encoder: latexEncoding :: ToLatex a => Exercise a -> Exercise a
+ Ideas.Encoding.Encoder: latexEncodingWith :: (a -> Latex) -> Exercise a -> Exercise a
+ Ideas.Encoding.Encoder: latexPrinter :: Exercise a -> a -> Latex
+ Ideas.Encoding.Encoder: latexPrinterContext :: Exercise a -> Context a -> Latex
+ Ideas.Encoding.LinkManager: makeLinkManager :: String -> String -> LinkManager
+ Ideas.Encoding.Logging: Record :: String -> String -> String -> String -> String -> String -> String -> String -> String -> String -> Time -> Diff -> String -> String -> String -> String -> String -> String -> String -> String -> Record
+ Ideas.Encoding.Logging: [binary] :: Record -> String
+ Ideas.Encoding.Logging: [dataformat] :: Record -> String
+ Ideas.Encoding.Logging: [encoding] :: Record -> String
+ Ideas.Encoding.Logging: [errormsg] :: Record -> String
+ Ideas.Encoding.Logging: [exerciseid] :: Record -> String
+ Ideas.Encoding.Logging: [input] :: Record -> String
+ Ideas.Encoding.Logging: [ipaddress] :: Record -> String
+ Ideas.Encoding.Logging: [output] :: Record -> String
+ Ideas.Encoding.Logging: [requestinfo] :: Record -> String
+ Ideas.Encoding.Logging: [responsetime] :: Record -> Diff
+ Ideas.Encoding.Logging: [ruleid] :: Record -> String
+ Ideas.Encoding.Logging: [script] :: Record -> String
+ Ideas.Encoding.Logging: [service] :: Record -> String
+ Ideas.Encoding.Logging: [serviceinfo] :: Record -> String
+ Ideas.Encoding.Logging: [sessionid] :: Record -> String
+ Ideas.Encoding.Logging: [source] :: Record -> String
+ Ideas.Encoding.Logging: [taskid] :: Record -> String
+ Ideas.Encoding.Logging: [time] :: Record -> Time
+ Ideas.Encoding.Logging: [userid] :: Record -> String
+ Ideas.Encoding.Logging: [version] :: Record -> String
+ Ideas.Encoding.Logging: addRequest :: Request -> Record -> Record
+ Ideas.Encoding.Logging: addState :: State a -> Record -> Record
+ Ideas.Encoding.Logging: changeLog :: LogRef -> (Record -> Record) -> IO ()
+ Ideas.Encoding.Logging: data LogRef
+ Ideas.Encoding.Logging: data Record
+ Ideas.Encoding.Logging: instance GHC.Show.Show Ideas.Encoding.Logging.Record
+ Ideas.Encoding.Logging: logEnabled :: Bool
+ Ideas.Encoding.Logging: logRecord :: Schema -> LogRef -> IO ()
+ Ideas.Encoding.Logging: newLogRef :: IO LogRef
+ Ideas.Encoding.Logging: noLogRef :: LogRef
+ Ideas.Encoding.Logging: printLog :: LogRef -> IO ()
+ Ideas.Encoding.Options: baseUrl :: Options -> Maybe String
+ Ideas.Encoding.Options: cgiBin :: Options -> Maybe String
+ Ideas.Encoding.Options: data Options
+ Ideas.Encoding.Options: instance GHC.Base.Monoid Ideas.Encoding.Options.Options
+ Ideas.Encoding.Options: makeOptions :: DomainReasoner -> Exercise a -> Request -> IO Options
+ Ideas.Encoding.Options: maxTime :: Options -> Maybe Int
+ Ideas.Encoding.Options: optionBaseUrl :: String -> Options
+ Ideas.Encoding.Options: optionCgiBin :: String -> Options
+ Ideas.Encoding.Options: optionHtml :: Options
+ Ideas.Encoding.Options: qcGen :: Options -> Maybe QCGen
+ Ideas.Encoding.Options: request :: Options -> Request
+ Ideas.Encoding.Options: script :: Options -> Script
+ Ideas.Encoding.Request: EncCompact :: Encoding
+ Ideas.Encoding.Request: EncHTML :: Encoding
+ Ideas.Encoding.Request: EncJSON :: Encoding
+ Ideas.Encoding.Request: EncOpenMath :: Encoding
+ Ideas.Encoding.Request: EncPretty :: Encoding
+ Ideas.Encoding.Request: EncString :: Encoding
+ Ideas.Encoding.Request: JSON :: DataFormat
+ Ideas.Encoding.Request: NoLogging :: Schema
+ Ideas.Encoding.Request: Request :: Maybe Id -> Maybe Id -> Maybe String -> Maybe String -> Maybe String -> Maybe String -> Maybe Schema -> Maybe Int -> Maybe DataFormat -> [Encoding] -> Request
+ Ideas.Encoding.Request: V1 :: Schema
+ Ideas.Encoding.Request: V2 :: Schema
+ Ideas.Encoding.Request: XML :: DataFormat
+ Ideas.Encoding.Request: [cgiBinary] :: Request -> Maybe String
+ Ideas.Encoding.Request: [dataformat] :: Request -> Maybe DataFormat
+ Ideas.Encoding.Request: [encoding] :: Request -> [Encoding]
+ Ideas.Encoding.Request: [exerciseId] :: Request -> Maybe Id
+ Ideas.Encoding.Request: [feedbackScript] :: Request -> Maybe String
+ Ideas.Encoding.Request: [logSchema] :: Request -> Maybe Schema
+ Ideas.Encoding.Request: [randomSeed] :: Request -> Maybe Int
+ Ideas.Encoding.Request: [requestInfo] :: Request -> Maybe String
+ Ideas.Encoding.Request: [serviceId] :: Request -> Maybe Id
+ Ideas.Encoding.Request: [source] :: Request -> Maybe String
+ Ideas.Encoding.Request: compactOutput :: Request -> Bool
+ Ideas.Encoding.Request: data DataFormat
+ Ideas.Encoding.Request: data Encoding
+ Ideas.Encoding.Request: data Request
+ Ideas.Encoding.Request: data Schema
+ Ideas.Encoding.Request: discoverDataFormat :: Monad m => String -> m DataFormat
+ Ideas.Encoding.Request: getSchema :: Request -> Schema
+ Ideas.Encoding.Request: htmlOutput :: Request -> Bool
+ Ideas.Encoding.Request: instance GHC.Base.Monoid Ideas.Encoding.Request.Request
+ Ideas.Encoding.Request: instance GHC.Classes.Eq Ideas.Encoding.Request.Encoding
+ Ideas.Encoding.Request: instance GHC.Classes.Eq Ideas.Encoding.Request.Schema
+ Ideas.Encoding.Request: instance GHC.Show.Show Ideas.Encoding.Request.DataFormat
+ Ideas.Encoding.Request: instance GHC.Show.Show Ideas.Encoding.Request.Encoding
+ Ideas.Encoding.Request: instance GHC.Show.Show Ideas.Encoding.Request.Schema
+ Ideas.Encoding.Request: readEncoding :: Monad m => String -> m [Encoding]
+ Ideas.Encoding.Request: readSchema :: Monad m => String -> m Schema
+ Ideas.Encoding.Request: useJSONTerm :: Request -> Bool
+ Ideas.Encoding.Request: useLogging :: Request -> Bool
+ Ideas.Encoding.Request: useOpenMath :: Request -> Bool
+ Ideas.Main.CmdLineOptions: AnalyzeScript :: FilePath -> CmdLineOption
+ Ideas.Main.CmdLineOptions: Help :: CmdLineOption
+ Ideas.Main.CmdLineOptions: InputFile :: String -> CmdLineOption
+ Ideas.Main.CmdLineOptions: MakeScriptFor :: String -> CmdLineOption
+ Ideas.Main.CmdLineOptions: PrintLog :: CmdLineOption
+ Ideas.Main.CmdLineOptions: Test :: FilePath -> CmdLineOption
+ Ideas.Main.CmdLineOptions: Version :: CmdLineOption
+ Ideas.Main.CmdLineOptions: data CmdLineOption
+ Ideas.Main.CmdLineOptions: fullVersion :: String
+ Ideas.Main.CmdLineOptions: getCmdLineOptions :: IO [CmdLineOption]
+ Ideas.Main.CmdLineOptions: helpText :: String
+ Ideas.Main.CmdLineOptions: instance GHC.Classes.Eq Ideas.Main.CmdLineOptions.CmdLineOption
+ Ideas.Main.CmdLineOptions: shortVersion :: String
+ Ideas.Main.CmdLineOptions: versionText :: String
+ Ideas.Main.Default: defaultMainWith :: Options -> DomainReasoner -> IO ()
+ Ideas.Service.BasicServices: onefinal :: State a -> Either String (Context a)
+ Ideas.Service.Diagnose: getState :: Diagnosis a -> Maybe (State a)
+ Ideas.Service.Diagnose: getStateAndReady :: Diagnosis a -> Maybe (State a, Bool)
+ Ideas.Service.Submit: getState :: Result a -> Maybe (State a)
+ Ideas.Service.Types: [:->] :: TypeRep f t1 -> TypeRep f t2 -> TypeRep f (t1 -> t2)
+ Ideas.Service.Types: [:::] :: t -> f t -> TypedValue f
+ Ideas.Service.Types: [:|:] :: TypeRep f t1 -> TypeRep f t2 -> TypeRep f (Either t1 t2)
+ Ideas.Service.Types: [Bool] :: Const a Bool
+ Ideas.Service.Types: [Const] :: f t -> TypeRep f t
+ Ideas.Service.Types: [Context] :: Const a (Context a)
+ Ideas.Service.Types: [Environment] :: Const a Environment
+ Ideas.Service.Types: [Exercise] :: Const a (Exercise a)
+ Ideas.Service.Types: [IO] :: TypeRep f t -> TypeRep f (IO t)
+ Ideas.Service.Types: [Id] :: Const a Id
+ Ideas.Service.Types: [Int] :: Const a Int
+ Ideas.Service.Types: [Iso] :: Isomorphism t1 t2 -> TypeRep f t1 -> TypeRep f t2
+ Ideas.Service.Types: [List] :: TypeRep f t -> TypeRep f [t]
+ Ideas.Service.Types: [Location] :: Const a Location
+ Ideas.Service.Types: [Pair] :: TypeRep f t1 -> TypeRep f t2 -> TypeRep f (t1, t2)
+ Ideas.Service.Types: [QCGen] :: Const a QCGen
+ Ideas.Service.Types: [Result] :: Const a Result
+ Ideas.Service.Types: [Rule] :: Const a (Rule (Context a))
+ Ideas.Service.Types: [Script] :: Const a Script
+ Ideas.Service.Types: [Service] :: Const a Service
+ Ideas.Service.Types: [SomeExercise] :: Const a (Some Exercise)
+ Ideas.Service.Types: [State] :: Const a (State a)
+ Ideas.Service.Types: [StratCfg] :: Const a StrategyCfg
+ Ideas.Service.Types: [Strategy] :: Const a (Strategy (Context a))
+ Ideas.Service.Types: [String] :: Const a String
+ Ideas.Service.Types: [Tag] :: String -> TypeRep f t1 -> TypeRep f t1
+ Ideas.Service.Types: [Term] :: Const a Term
+ Ideas.Service.Types: [Text] :: Const a Text
+ Ideas.Service.Types: [Unit] :: TypeRep f ()
+ Ideas.Service.Types: infixr 5 .->
+ Ideas.Text.Latex: (<>) :: Monoid m => m -> m -> m
+ Ideas.Text.Latex: array :: String -> [[Latex]] -> Latex
+ Ideas.Text.Latex: brackets :: Latex -> Latex
+ Ideas.Text.Latex: class ToLatex a where toLatex = toLatexPrec 0 toLatexPrec = const toLatex toLatexList = brackets . commas . map toLatex
+ Ideas.Text.Latex: command :: String -> Latex
+ Ideas.Text.Latex: commas :: [Latex] -> Latex
+ Ideas.Text.Latex: data Latex
+ Ideas.Text.Latex: infixr 6 <>
+ Ideas.Text.Latex: instance Data.String.IsString Ideas.Text.Latex.Latex
+ Ideas.Text.Latex: instance GHC.Base.Monoid Ideas.Text.Latex.Latex
+ Ideas.Text.Latex: instance GHC.Show.Show Ideas.Text.Latex.Latex
+ Ideas.Text.Latex: instance Ideas.Text.Latex.ToLatex GHC.Types.Char
+ Ideas.Text.Latex: instance Ideas.Text.Latex.ToLatex GHC.Types.Int
+ Ideas.Text.Latex: instance Ideas.Text.Latex.ToLatex a => Ideas.Text.Latex.ToLatex (GHC.Base.Maybe a)
+ Ideas.Text.Latex: instance Ideas.Text.Latex.ToLatex a => Ideas.Text.Latex.ToLatex [a]
+ Ideas.Text.Latex: parens :: Latex -> Latex
+ Ideas.Text.Latex: toLatex :: ToLatex a => a -> Latex
+ Ideas.Text.Latex: toLatexList :: ToLatex a => [a] -> Latex
+ Ideas.Text.Latex: toLatexPrec :: ToLatex a => Int -> a -> Latex
+ Ideas.Text.XML.Document: newtype Parameter
+ Ideas.Utils.BlackBoxTests: blackBoxTests :: TestRunner -> [String] -> String -> IO TestSuite
+ Ideas.Utils.BlackBoxTests: type TestRunner = String -> IO String
+ Ideas.Utils.Parsing: (*>) :: Applicative f => forall a b. f a -> f b -> f b
+ Ideas.Utils.Parsing: (<$) :: Functor f => forall a b. a -> f b -> f a
+ Ideas.Utils.Parsing: (<$>) :: Functor f => (a -> b) -> f a -> f b
+ Ideas.Utils.Parsing: (<*) :: Applicative f => forall a b. f a -> f b -> f a
+ Ideas.Utils.Parsing: (<**>) :: Applicative f => f a -> f (a -> b) -> f b
+ Ideas.Utils.Parsing: (<*>) :: Applicative f => forall a b. f (a -> b) -> f a -> f b
+ Ideas.Utils.Parsing: (<..>) :: Char -> Char -> Parser Char
+ Ideas.Utils.Parsing: NotClosed :: SourcePos -> Char -> UnbalancedError
+ Ideas.Utils.Parsing: NotOpened :: SourcePos -> Char -> UnbalancedError
+ Ideas.Utils.Parsing: balanced :: [(Char, Char)] -> String -> Maybe UnbalancedError
+ Ideas.Utils.Parsing: complete :: Parser a -> Parser a
+ Ideas.Utils.Parsing: data UnbalancedError
+ Ideas.Utils.Parsing: float :: Parser Double
+ Ideas.Utils.Parsing: infix 6 <..>
+ Ideas.Utils.Parsing: infixl 4 <**>
+ Ideas.Utils.Parsing: instance GHC.Show.Show Ideas.Utils.Parsing.UnbalancedError
+ Ideas.Utils.Parsing: naturalOrFloat :: Parser (Either Integer Double)
+ Ideas.Utils.Parsing: parseSimple :: Parser a -> String -> Either String a
+ Ideas.Utils.Parsing: ranges :: [(Char, Char)] -> Parser Char
+ Ideas.Utils.Parsing: skip :: Parser a -> Parser ()
+ Ideas.Utils.Parsing: stopOn :: [String] -> Parser String
+ Ideas.Utils.Prelude: ShowString :: String -> ShowString
+ Ideas.Utils.Prelude: Some :: (f a) -> Some f
+ Ideas.Utils.Prelude: [fromShowString] :: ShowString -> String
+ Ideas.Utils.Prelude: allsame :: Eq a => [a] -> Bool
+ Ideas.Utils.Prelude: cartesian :: [a] -> [b] -> [(a, b)]
+ Ideas.Utils.Prelude: changeAt :: Monad m => Int -> (a -> a) -> [a] -> m [a]
+ Ideas.Utils.Prelude: data Some f
+ Ideas.Utils.Prelude: distinct :: Eq a => [a] -> Bool
+ Ideas.Utils.Prelude: elementAt :: Monad m => Int -> [a] -> m a
+ Ideas.Utils.Prelude: findIndexM :: Monad m => (a -> Bool) -> [a] -> m Int
+ Ideas.Utils.Prelude: fixpoint :: Eq a => (a -> a) -> a -> a
+ Ideas.Utils.Prelude: fst3 :: (a, b, c) -> a
+ Ideas.Utils.Prelude: headM :: Monad m => [a] -> m a
+ Ideas.Utils.Prelude: instance GHC.Classes.Eq Ideas.Utils.Prelude.ShowString
+ Ideas.Utils.Prelude: instance GHC.Classes.Ord Ideas.Utils.Prelude.ShowString
+ Ideas.Utils.Prelude: instance GHC.Read.Read Ideas.Utils.Prelude.ShowString
+ Ideas.Utils.Prelude: instance GHC.Show.Show Ideas.Utils.Prelude.ShowString
+ Ideas.Utils.Prelude: isSubsetOf :: Eq a => [a] -> [a] -> Bool
+ Ideas.Utils.Prelude: list :: b -> ([a] -> b) -> [a] -> b
+ Ideas.Utils.Prelude: newtype ShowString
+ Ideas.Utils.Prelude: readInt :: String -> Maybe Int
+ Ideas.Utils.Prelude: readM :: (Monad m, Read a) => String -> m a
+ Ideas.Utils.Prelude: replaceAt :: Monad m => Int -> a -> [a] -> m [a]
+ Ideas.Utils.Prelude: snd3 :: (a, b, c) -> b
+ Ideas.Utils.Prelude: splitAtElem :: Eq a => a -> [a] -> Maybe ([a], [a])
+ Ideas.Utils.Prelude: splitsWithElem :: Eq a => a -> [a] -> [[a]]
+ Ideas.Utils.Prelude: subsets :: [a] -> [[a]]
+ Ideas.Utils.Prelude: thd3 :: (a, b, c) -> c
+ Ideas.Utils.Prelude: timedSeconds :: Int -> IO a -> IO a
+ Ideas.Utils.QuickCheck: arbGen :: Arbitrary b => (b -> a) -> ArbGen a
+ Ideas.Utils.QuickCheck: binaryGen :: (a -> a -> a) -> ArbGen a
+ Ideas.Utils.QuickCheck: binaryGens :: [a -> a -> a] -> ArbGen a
+ Ideas.Utils.QuickCheck: changeFrequency :: Rational -> ArbGen a -> ArbGen a
+ Ideas.Utils.QuickCheck: common :: ArbGen a -> ArbGen a
+ Ideas.Utils.QuickCheck: constGen :: a -> ArbGen a
+ Ideas.Utils.QuickCheck: constGens :: [a] -> ArbGen a
+ Ideas.Utils.QuickCheck: data ArbGen a
+ Ideas.Utils.QuickCheck: generator :: ArbGen a -> Gen a
+ Ideas.Utils.QuickCheck: generators :: [ArbGen a] -> Gen a
+ Ideas.Utils.QuickCheck: instance GHC.Base.Monoid (Ideas.Utils.QuickCheck.ArbGen a)
+ Ideas.Utils.QuickCheck: rare :: ArbGen a -> ArbGen a
+ Ideas.Utils.QuickCheck: toArbGen :: Gen a -> ArbGen a
+ Ideas.Utils.QuickCheck: unaryArbGen :: Arbitrary b => (b -> a -> a) -> ArbGen a
+ Ideas.Utils.QuickCheck: unaryGen :: (a -> a) -> ArbGen a
+ Ideas.Utils.QuickCheck: unaryGens :: [a -> a] -> ArbGen a
+ Ideas.Utils.QuickCheck: uncommon :: ArbGen a -> ArbGen a
+ Ideas.Utils.StringRef: data StringRef
+ Ideas.Utils.StringRef: instance GHC.Classes.Eq Ideas.Utils.StringRef.StringRef
+ Ideas.Utils.StringRef: instance GHC.Classes.Ord Ideas.Utils.StringRef.StringRef
+ Ideas.Utils.StringRef: stringRef :: String -> StringRef
+ Ideas.Utils.StringRef: tableStatus :: IO String
+ Ideas.Utils.StringRef: toString :: StringRef -> String
+ Ideas.Utils.TestSuite: allMessages :: Result -> [(String, Message)]
+ Ideas.Utils.TestSuite: assertEquals :: (Eq a, Show a) => String -> a -> a -> TestSuite
+ Ideas.Utils.TestSuite: assertIO :: String -> IO Bool -> TestSuite
+ Ideas.Utils.TestSuite: assertMessage :: String -> Bool -> String -> TestSuite
+ Ideas.Utils.TestSuite: assertMessageIO :: String -> IO Message -> TestSuite
+ Ideas.Utils.TestSuite: assertNull :: Show a => String -> [a] -> TestSuite
+ Ideas.Utils.TestSuite: assertTrue :: String -> Bool -> TestSuite
+ Ideas.Utils.TestSuite: class HasRating a
+ Ideas.Utils.TestSuite: class HasStatus a
+ Ideas.Utils.TestSuite: data Message
+ Ideas.Utils.TestSuite: data Rating
+ Ideas.Utils.TestSuite: data Result
+ Ideas.Utils.TestSuite: data Status
+ Ideas.Utils.TestSuite: data TestSuite
+ Ideas.Utils.TestSuite: findSubResult :: String -> Result -> Maybe Result
+ Ideas.Utils.TestSuite: getStatus :: HasStatus a => a -> Status
+ Ideas.Utils.TestSuite: instance GHC.Base.Monoid Ideas.Utils.TestSuite.Message
+ Ideas.Utils.TestSuite: instance GHC.Base.Monoid Ideas.Utils.TestSuite.Rating
+ Ideas.Utils.TestSuite: instance GHC.Base.Monoid Ideas.Utils.TestSuite.Result
+ Ideas.Utils.TestSuite: instance GHC.Base.Monoid Ideas.Utils.TestSuite.Status
+ Ideas.Utils.TestSuite: instance GHC.Base.Monoid Ideas.Utils.TestSuite.TestSuite
+ Ideas.Utils.TestSuite: instance GHC.Classes.Eq Ideas.Utils.TestSuite.Message
+ Ideas.Utils.TestSuite: instance GHC.Classes.Eq Ideas.Utils.TestSuite.Rating
+ Ideas.Utils.TestSuite: instance GHC.Classes.Eq Ideas.Utils.TestSuite.Status
+ Ideas.Utils.TestSuite: instance GHC.Classes.Ord Ideas.Utils.TestSuite.Rating
+ Ideas.Utils.TestSuite: instance GHC.Classes.Ord Ideas.Utils.TestSuite.Status
+ Ideas.Utils.TestSuite: instance GHC.Show.Show Ideas.Utils.TestSuite.Message
+ Ideas.Utils.TestSuite: instance GHC.Show.Show Ideas.Utils.TestSuite.Result
+ Ideas.Utils.TestSuite: instance Ideas.Utils.TestSuite.HasRating Ideas.Utils.TestSuite.Message
+ Ideas.Utils.TestSuite: instance Ideas.Utils.TestSuite.HasRating Ideas.Utils.TestSuite.Rating
+ Ideas.Utils.TestSuite: instance Ideas.Utils.TestSuite.HasRating Ideas.Utils.TestSuite.Result
+ Ideas.Utils.TestSuite: instance Ideas.Utils.TestSuite.HasStatus Ideas.Utils.TestSuite.Message
+ Ideas.Utils.TestSuite: instance Ideas.Utils.TestSuite.HasStatus Ideas.Utils.TestSuite.Result
+ Ideas.Utils.TestSuite: isError :: HasStatus a => a -> Bool
+ Ideas.Utils.TestSuite: isOk :: HasStatus a => a -> Bool
+ Ideas.Utils.TestSuite: isWarning :: HasStatus a => a -> Bool
+ Ideas.Utils.TestSuite: justOneSuite :: Result -> Maybe (String, Result)
+ Ideas.Utils.TestSuite: makeSummary :: Result -> String
+ Ideas.Utils.TestSuite: message :: String -> Message
+ Ideas.Utils.TestSuite: messageLines :: Message -> [String]
+ Ideas.Utils.TestSuite: nrOfErrors :: Result -> Int
+ Ideas.Utils.TestSuite: nrOfTests :: Result -> Int
+ Ideas.Utils.TestSuite: nrOfWarnings :: Result -> Int
+ Ideas.Utils.TestSuite: onlyWarnings :: TestSuite -> TestSuite
+ Ideas.Utils.TestSuite: printSummary :: Result -> IO ()
+ Ideas.Utils.TestSuite: rate :: HasRating a => Int -> a -> a
+ Ideas.Utils.TestSuite: rateOnError :: Int -> TestSuite -> TestSuite
+ Ideas.Utils.TestSuite: rating :: HasRating a => a -> Maybe Int
+ Ideas.Utils.TestSuite: runTestSuite :: Bool -> TestSuite -> IO ()
+ Ideas.Utils.TestSuite: runTestSuiteResult :: Bool -> TestSuite -> IO Result
+ Ideas.Utils.TestSuite: subResults :: Result -> [(String, Result)]
+ Ideas.Utils.TestSuite: suite :: String -> [TestSuite] -> TestSuite
+ Ideas.Utils.TestSuite: timeInterval :: Result -> Double
+ Ideas.Utils.TestSuite: topMessages :: Result -> [(String, Message)]
+ Ideas.Utils.TestSuite: useProperty :: Testable prop => String -> prop -> TestSuite
+ Ideas.Utils.TestSuite: usePropertyWith :: Testable prop => String -> Args -> prop -> TestSuite
+ Ideas.Utils.TestSuite: warning :: String -> Message
+ Ideas.Utils.Typeable: castBetween :: (HasTypeable f, HasTypeable g) => f a -> g b -> a -> Maybe b
+ Ideas.Utils.Typeable: castFrom :: (HasTypeable f, Typeable b) => f a -> a -> Maybe b
+ Ideas.Utils.Typeable: castTo :: (HasTypeable f, Typeable a) => f b -> a -> Maybe b
+ Ideas.Utils.Typeable: class HasTypeable f
+ Ideas.Utils.Typeable: data IsTypeable a
+ Ideas.Utils.Typeable: gcastBetween :: (HasTypeable f, HasTypeable g) => f a -> g b -> c a -> Maybe (c b)
+ Ideas.Utils.Typeable: gcastFrom :: (HasTypeable f, Typeable b) => f a -> c a -> Maybe (c b)
+ Ideas.Utils.Typeable: gcastTo :: (HasTypeable f, Typeable a) => f b -> c a -> Maybe (c b)
+ Ideas.Utils.Typeable: getTypeable :: HasTypeable f => f a -> Maybe (IsTypeable a)
+ Ideas.Utils.Typeable: instance Ideas.Utils.Typeable.HasTypeable Ideas.Utils.Typeable.IsTypeable
+ Ideas.Utils.Typeable: typeable :: forall a. Typeable a => IsTypeable a
+ Ideas.Utils.Uniplate: (|*) :: Type (to -> from) to -> to -> Type from to
+ Ideas.Utils.Uniplate: (|-) :: Type (item -> from) to -> item -> Type from to
+ Ideas.Utils.Uniplate: (||*) :: Type ([to] -> from) to -> [to] -> Type from to
+ Ideas.Utils.Uniplate: children :: Uniplate on => on -> [on]
+ Ideas.Utils.Uniplate: class Uniplate on
+ Ideas.Utils.Uniplate: contexts :: Uniplate on => on -> [(on, on -> on)]
+ Ideas.Utils.Uniplate: descend :: Uniplate on => (on -> on) -> on -> on
+ Ideas.Utils.Uniplate: descendM :: Uniplate on => forall (m :: * -> *). Monad m => (on -> m on) -> on -> m on
+ Ideas.Utils.Uniplate: holes :: Uniplate on => on -> [(on, on -> on)]
+ Ideas.Utils.Uniplate: para :: Uniplate on => (on -> [r] -> r) -> on -> r
+ Ideas.Utils.Uniplate: plate :: from -> Type from to
+ Ideas.Utils.Uniplate: rewrite :: Uniplate on => (on -> Maybe on) -> on -> on
+ Ideas.Utils.Uniplate: rewriteM :: (Monad m, Uniplate on) => (on -> m (Maybe on)) -> on -> m on
+ Ideas.Utils.Uniplate: transform :: Uniplate on => (on -> on) -> on -> on
+ Ideas.Utils.Uniplate: transformM :: (Monad m, Uniplate on) => (on -> m on) -> on -> m on
+ Ideas.Utils.Uniplate: uniplate :: Uniplate on => on -> (Str on, Str on -> on)
+ Ideas.Utils.Uniplate: universe :: Uniplate on => on -> [on]
- Ideas.Common.Environment: (?) :: (HasEnvironment env, Typeable a) => Ref a -> env -> Maybe a
+ Ideas.Common.Environment: (?) :: HasEnvironment env => Ref a -> env -> Maybe a
- Ideas.Common.Environment: changeRef :: (HasEnvironment env, Typeable a) => Ref a -> (a -> a) -> env -> env
+ Ideas.Common.Environment: changeRef :: HasEnvironment env => Ref a -> (a -> a) -> env -> env
- Ideas.Common.Environment: class HasEnvironment env where deleteRef a = changeEnv (Env . delete (getId a) . envMap) insertRef ref = let f b = Env . insert (getId b) b . envMap in changeEnv . f . Binding ref changeRef ref f env = maybe id (insertRef ref . f) (ref ? env) env
+ Ideas.Common.Environment: class HasEnvironment env where deleteRef a = changeEnv (Env . delete (getId a) . envMap) insertRef r = let f b = Env . insert (getId b) b . envMap in changeEnv . f . Binding r changeRef r f env = maybe id (insertRef r . f) (r ? env) env
- Ideas.Common.Environment: class (IsTerm a, Typeable a, Show a, Read a) => Reference a where makeRef n = Ref (newId n) show readM termView makeRefList n = Ref (newId n) show readM termView
+ Ideas.Common.Environment: class (IsTerm a, Typeable a, Show a, Read a) => Reference a where makeRef n = Ref (newId n) show readM termView typeable makeRefList n = Ref (newId n) show readM termView typeable
- Ideas.Common.Environment: insertRef :: (HasEnvironment env, Typeable a) => Ref a -> a -> env -> env
+ Ideas.Common.Environment: insertRef :: HasEnvironment env => Ref a -> a -> env -> env
- Ideas.Common.Environment: makeBinding :: Typeable a => Ref a -> a -> Binding
+ Ideas.Common.Environment: makeBinding :: Ref a -> a -> Binding
- Ideas.Common.Environment: singleBinding :: Typeable a => Ref a -> a -> Environment
+ Ideas.Common.Environment: singleBinding :: Ref a -> a -> Environment
- Ideas.Common.Exercise: NewExercise :: Id -> Status -> (String -> Either String a) -> (a -> String) -> (Context a -> Context a -> Bool) -> (Context a -> Context a -> Bool) -> Predicate a -> Predicate a -> LabeledStrategy (Context a) -> Bool -> [Rule (Context a)] -> (Rule (Context a) -> Rule (Context a) -> Ordering) -> (a -> ContextNavigator a) -> Examples a -> Maybe (QCGen -> Maybe Difficulty -> a) -> Maybe (Gen a) -> Maybe (View Term a) -> Maybe (IsTypeable a) -> Map String Dynamic -> Exercise a
+ Ideas.Common.Exercise: NewExercise :: Id -> Status -> (String -> Either String a) -> (a -> String) -> (Context a -> Context a -> Bool) -> (Context a -> Context a -> Bool) -> Predicate a -> Predicate a -> LabeledStrategy (Context a) -> Bool -> [Rule (Context a)] -> (Rule (Context a) -> Rule (Context a) -> Ordering) -> (a -> ContextNavigator a) -> Examples a -> Maybe (QCGen -> Maybe Difficulty -> a) -> Maybe (Gen a) -> Maybe (View Term a) -> Maybe (IsTypeable a) -> Map Id (Dynamic a) -> Exercise a
- Ideas.Common.Exercise: [properties] :: Exercise a -> Map String Dynamic
+ Ideas.Common.Exercise: [properties] :: Exercise a -> Map Id (Dynamic a)
- Ideas.Common.Exercise: castFrom :: Typeable b => Exercise a -> a -> Maybe b
+ Ideas.Common.Exercise: castFrom :: (HasTypeable f, Typeable b) => f a -> a -> Maybe b
- Ideas.Common.Exercise: castTo :: Typeable b => Exercise a -> b -> Maybe a
+ Ideas.Common.Exercise: castTo :: (HasTypeable f, Typeable a) => f b -> a -> Maybe b
- Ideas.Common.Exercise: getProperty :: Typeable val => String -> Exercise a -> Maybe val
+ Ideas.Common.Exercise: getProperty :: (IsId n, Typeable val) => n -> Exercise a -> Maybe val
- Ideas.Common.Exercise: setProperty :: Typeable val => String -> val -> Exercise a -> Exercise a
+ Ideas.Common.Exercise: setProperty :: (IsId n, Typeable val) => n -> val -> Exercise a -> Exercise a
- Ideas.Common.Rewriting.Term: class IsTerm a
+ Ideas.Common.Rewriting.Term: class IsTerm a where toTermList = TList . map toTerm fromTermList (TList xs) = mapM fromTerm xs fromTermList _ = fail "fromTermList: not a list"
- Ideas.Common.Rule.Parameter: parameter1 :: (IsId n1, Reference a) => n1 -> (a -> Transformation b) -> ParamTrans a b
+ Ideas.Common.Rule.Parameter: parameter1 :: Ref a -> (a -> b -> Maybe b) -> ParamTrans a b
- Ideas.Common.Rule.Parameter: parameter2 :: (IsId n1, IsId n2, Reference a, Reference b) => n1 -> n2 -> (a -> b -> Transformation c) -> ParamTrans (a, b) c
+ Ideas.Common.Rule.Parameter: parameter2 :: Ref a -> Ref b -> (a -> b -> c -> Maybe c) -> ParamTrans (a, b) c
- Ideas.Common.Rule.Parameter: parameter3 :: (IsId n1, IsId n2, IsId n3, Reference a, Reference b, Reference c) => n1 -> n2 -> n3 -> (a -> b -> c -> Transformation d) -> ParamTrans (a, b, c) d
+ Ideas.Common.Rule.Parameter: parameter3 :: Ref a -> Ref b -> Ref c -> (a -> b -> c -> d -> Maybe d) -> ParamTrans (a, b, c) d
- Ideas.Common.Rule.Parameter: supplyParameters :: ParamTrans b a -> (a -> Maybe b) -> Transformation a
+ Ideas.Common.Rule.Parameter: supplyParameters :: ParamTrans b a -> Trans a b -> Transformation (Context a)
- Ideas.Common.Rule.Parameter: type ParamTrans a b = Trans (a, b) b
+ Ideas.Common.Rule.Parameter: type ParamTrans i a = Trans (i, a) a
- Ideas.Common.Strategy.Abstract: mapRules :: (Rule a -> Rule b) -> LabeledStrategy a -> LabeledStrategy b
+ Ideas.Common.Strategy.Abstract: mapRules :: (Rule a -> Rule a) -> LabeledStrategy a -> LabeledStrategy a
- Ideas.Common.Strategy.Abstract: mapRulesS :: (Rule a -> Rule b) -> Strategy a -> Strategy b
+ Ideas.Common.Strategy.Abstract: mapRulesS :: (Rule a -> Rule a) -> Strategy a -> Strategy a
- Ideas.Common.Strategy.Prefix: makePrefix :: Process (Rule a) -> a -> Prefix a
+ Ideas.Common.Strategy.Prefix: makePrefix :: Process (Leaf a) -> a -> Prefix a
- Ideas.Common.Strategy.Prefix: replayProcess :: Path -> Process (Rule a) -> ([Rule a], a -> Prefix a)
+ Ideas.Common.Strategy.Prefix: replayProcess :: Path -> Process (Leaf a) -> ([Rule a], a -> Prefix a)
- Ideas.Common.Strategy.Sequence: class Firsts s where type family Elem s
+ Ideas.Common.Strategy.Sequence: class Firsts s where type Elem s where {
- Ideas.Common.Strategy.Sequence: class Sequence a where type family Sym a single s = s ~> done sequence xs = if null xs then done else foldr1 (.*.) xs
+ Ideas.Common.Strategy.Sequence: class Sequence a where type Sym a single s = s ~> done sequence xs = if null xs then done else foldr1 (.*.) xs where {
- Ideas.Common.Strategy.StrategyTree: type Combinator f = forall a. f (Process (Rule a))
+ Ideas.Common.Strategy.StrategyTree: type Combinator f = forall a. f (Process (Leaf a))
- Ideas.Common.Strategy.StrategyTree: type StrategyTree a = CyclicTree (Decl Nary) (Rule a)
+ Ideas.Common.Strategy.StrategyTree: type StrategyTree a = CyclicTree (Decl Nary) (Leaf a)
- Ideas.Common.Traversal.Navigator: class Navigator a where downLast = liftM (fixp right) . down childnr = pred . length . fixpl left location = toLocation . map childnr . drop 1 . reverse . fixpl up
+ Ideas.Common.Traversal.Navigator: class Navigator a where downLast = fmap (fixp right) . down childnr = pred . length . fixpl left location = toLocation . map childnr . drop 1 . reverse . fixpl up
- Ideas.Common.Traversal.Utils: class Focus a where type family Unfocus a focus = fromMaybe (error "no focus") . focusM focusM = Just . focus
+ Ideas.Common.Traversal.Utils: class Focus a where type Unfocus a focus = fromMaybe (error "no focus") . focusM focusM = Just . focus where {
- Ideas.Encoding.Encoder: fromOptions :: Converter f => (Options a -> t) -> f a s t
+ Ideas.Encoding.Encoder: fromOptions :: Converter f => (Options -> t) -> f a s t
- Ideas.Encoding.Encoder: run :: (Converter f, Monad m) => f a s t -> Options a -> s -> m t
+ Ideas.Encoding.Encoder: run :: (Converter f, Monad m) => f a s t -> Exercise a -> Options -> s -> m t
- Ideas.Encoding.Evaluator: evalService :: LogRef -> Options a -> Evaluator a b c -> Service -> b -> IO c
+ Ideas.Encoding.Evaluator: evalService :: LogRef -> Exercise a -> Options -> Evaluator a b c -> Service -> b -> IO c
- Ideas.Encoding.LinkManager: LinkManager :: (String -> String) -> (String -> String) -> String -> Bool -> String -> String -> String -> (Service -> String) -> (forall a. Exercise a -> String) -> (forall a. Exercise a -> String) -> (forall a. Exercise a -> String) -> (forall a. Exercise a -> String) -> (forall a. Exercise a -> String) -> (forall a. Exercise a -> Rule (Context a) -> String) -> (forall a. Exercise a -> String) -> (forall a. Exercise a -> Difficulty -> String) -> (forall a. State a -> String) -> (forall a. State a -> String) -> (forall a. State a -> String) -> (forall a. State a -> String) -> (forall a. State a -> String) -> LinkManager
+ Ideas.Encoding.LinkManager: LinkManager :: (String -> String) -> (String -> String) -> String -> String -> String -> String -> (Service -> String) -> (forall a. Exercise a -> String) -> (forall a. Exercise a -> String) -> (forall a. Exercise a -> String) -> (forall a. Exercise a -> String) -> (forall a. Exercise a -> String) -> (forall a. Exercise a -> Rule (Context a) -> String) -> (forall a. Exercise a -> String) -> (forall a. Exercise a -> Difficulty -> String) -> (forall a. State a -> String) -> (forall a. State a -> String) -> (forall a. State a -> String) -> (forall a. State a -> String) -> (forall a. State a -> String) -> LinkManager
- Ideas.Encoding.ModeJSON: processJSON :: Maybe Int -> Maybe String -> DomainReasoner -> LogRef -> String -> IO (Request, String, String)
+ Ideas.Encoding.ModeJSON: processJSON :: Options -> DomainReasoner -> LogRef -> String -> IO (Request, String, String)
- Ideas.Encoding.ModeXML: processXML :: Maybe Int -> Maybe String -> DomainReasoner -> LogRef -> String -> IO (Request, String, String)
+ Ideas.Encoding.ModeXML: processXML :: Options -> DomainReasoner -> LogRef -> String -> IO (Request, String, String)
- Ideas.Main.Default: defaultCGI :: DomainReasoner -> IO ()
+ Ideas.Main.Default: defaultCGI :: Options -> DomainReasoner -> IO ()
Files
- CHANGELOG.txt +22/−0
- ideas.cabal +15/−22
- src/Ideas/Common/Algebra/Boolean.hs +0/−164
- src/Ideas/Common/Algebra/BooleanLaws.hs +0/−108
- src/Ideas/Common/Algebra/Field.hs +0/−237
- src/Ideas/Common/Algebra/FieldLaws.hs +0/−111
- src/Ideas/Common/Algebra/Group.hs +0/−196
- src/Ideas/Common/Algebra/GroupLaws.hs +0/−150
- src/Ideas/Common/Algebra/Law.hs +0/−78
- src/Ideas/Common/Algebra/SmartGroup.hs +0/−198
- src/Ideas/Common/Classes.hs +57/−0
- src/Ideas/Common/Context.hs +8/−9
- src/Ideas/Common/CyclicTree.hs +0/−218
- src/Ideas/Common/Environment.hs +43/−31
- src/Ideas/Common/Exercise.hs +46/−30
- src/Ideas/Common/ExerciseTests.hs +3/−3
- src/Ideas/Common/Id.hs +2/−5
- src/Ideas/Common/Library.hs +2/−1
- src/Ideas/Common/Predicate.hs +1/−1
- src/Ideas/Common/Rewriting/Confluence.hs +1/−1
- src/Ideas/Common/Rewriting/RewriteRule.hs +1/−1
- src/Ideas/Common/Rewriting/Substitution.hs +3/−3
- src/Ideas/Common/Rewriting/Term.hs +51/−17
- src/Ideas/Common/Rewriting/Unification.hs +2/−2
- src/Ideas/Common/Rule.hs +0/−1
- src/Ideas/Common/Rule/Abstract.hs +2/−9
- src/Ideas/Common/Rule/EnvironmentMonad.hs +0/−132
- src/Ideas/Common/Rule/Parameter.hs +100/−25
- src/Ideas/Common/Rule/Recognizer.hs +3/−7
- src/Ideas/Common/Rule/Transformation.hs +59/−57
- src/Ideas/Common/Strategy.hs +1/−1
- src/Ideas/Common/Strategy/Abstract.hs +18/−16
- src/Ideas/Common/Strategy/Combinators.hs +8/−3
- src/Ideas/Common/Strategy/Configuration.hs +8/−8
- src/Ideas/Common/Strategy/CyclicTree.hs +217/−0
- src/Ideas/Common/Strategy/Derived.hs +16/−44
- src/Ideas/Common/Strategy/Location.hs +1/−1
- src/Ideas/Common/Strategy/Prefix.hs +43/−15
- src/Ideas/Common/Strategy/StrategyTree.hs +97/−9
- src/Ideas/Common/Traversal/Navigator.hs +11/−11
- src/Ideas/Common/Traversal/Tests.hs +11/−11
- src/Ideas/Common/Traversal/Utils.hs +5/−5
- src/Ideas/Common/Utils.hs +0/−128
- src/Ideas/Common/Utils/QuickCheck.hs +0/−102
- src/Ideas/Common/Utils/StringRef.hs +0/−136
- src/Ideas/Common/Utils/TestSuite.hs +0/−420
- src/Ideas/Common/Utils/Uniplate.hs +0/−25
- src/Ideas/Common/View.hs +1/−2
- src/Ideas/Encoding/DecoderJSON.hs +9/−8
- src/Ideas/Encoding/DecoderXML.hs +7/−8
- src/Ideas/Encoding/Encoder.hs +117/−99
- src/Ideas/Encoding/EncoderHTML.hs +35/−30
- src/Ideas/Encoding/EncoderJSON.hs +8/−11
- src/Ideas/Encoding/EncoderXML.hs +1/−2
- src/Ideas/Encoding/Evaluator.hs +9/−8
- src/Ideas/Encoding/LinkManager.hs +11/−88
- src/Ideas/Encoding/Logging.hs +187/−0
- src/Ideas/Encoding/ModeJSON.hs +29/−25
- src/Ideas/Encoding/ModeXML.hs +26/−21
- src/Ideas/Encoding/OpenMathSupport.hs +3/−3
- src/Ideas/Encoding/Options.hs +73/−0
- src/Ideas/Encoding/Request.hs +130/−0
- src/Ideas/Encoding/RulePresenter.hs +0/−1
- src/Ideas/Encoding/RulesInfo.hs +0/−1
- src/Ideas/Encoding/StrategyInfo.hs +1/−1
- src/Ideas/Main/BlackBoxTests.hs +0/−116
- src/Ideas/Main/CmdLineOptions.hs +80/−0
- src/Ideas/Main/Default.hs +46/−33
- src/Ideas/Main/Documentation.hs +0/−62
- src/Ideas/Main/Logging.hs +0/−187
- src/Ideas/Main/Options.hs +0/−83
- src/Ideas/Main/Revision.hs +3/−3
- src/Ideas/Service/BasicServices.hs +38/−7
- src/Ideas/Service/Diagnose.hs +16/−11
- src/Ideas/Service/DomainReasoner.hs +3/−9
- src/Ideas/Service/FeedbackScript/Analysis.hs +1/−2
- src/Ideas/Service/FeedbackScript/Parser.hs +1/−1
- src/Ideas/Service/FeedbackScript/Run.hs +6/−7
- src/Ideas/Service/FeedbackScript/Syntax.hs +1/−1
- src/Ideas/Service/FeedbackText.hs +4/−4
- src/Ideas/Service/ProblemDecomposition.hs +1/−1
- src/Ideas/Service/Request.hs +0/−115
- src/Ideas/Service/ServiceList.hs +7/−2
- src/Ideas/Service/Submit.hs +10/−1
- src/Ideas/Service/Types.hs +1/−2
- src/Ideas/Text/HTML.hs +1/−1
- src/Ideas/Text/JSON.hs +8/−8
- src/Ideas/Text/Latex.hs +75/−0
- src/Ideas/Text/OpenMath/Object.hs +4/−4
- src/Ideas/Text/OpenMath/Tests.hs +5/−5
- src/Ideas/Text/Parsing.hs +0/−120
- src/Ideas/Text/UTF8.hs +3/−3
- src/Ideas/Text/XML.hs +6/−3
- src/Ideas/Text/XML/Document.hs +1/−1
- src/Ideas/Text/XML/Interface.hs +1/−1
- src/Ideas/Text/XML/Parser.hs +1/−1
- src/Ideas/Utils/BlackBoxTests.hs +110/−0
- src/Ideas/Utils/Parsing.hs +120/−0
- src/Ideas/Utils/Prelude.hs +127/−0
- src/Ideas/Utils/QuickCheck.hs +102/−0
- src/Ideas/Utils/StringRef.hs +134/−0
- src/Ideas/Utils/TestSuite.hs +420/−0
- src/Ideas/Utils/Typeable.hs +70/−0
- src/Ideas/Utils/Uniplate.hs +25/−0
CHANGELOG.txt view
@@ -1,3 +1,25 @@+Changelog ideas-1.5 => ideas.1.6++* dynamic strategy combinator that uses the current object/term+* more instances for IsTerm (Maybe, Bool, Map, Set)+* exercise-specific properties (that can be parameterized over its type)+* support for encoding exercise terms in JSON (using an exercise property)+* basic support for Latex and MathJax (in html output)+* extended 'apply' feedback service with buggy rules and restarts+* redesigned (parameterized) transformations+* reimplemented strategy combinator split, based on %>>+* new function defaultMainWith, which takes options+* added 'onefinal' feedback service, which returns a final term in context+* layered design for sub-directories: renaming/moving some modules + (e.g. Ideas.Utils.Prelude)+* Typeable constraint now properly encapsulated in Ref type+* removing (static) documentation generation (unused feature)+* removing Common.Algebra modules (now in the Math domain reasoner)+* fixed escaping of characters in xml+* fixed recognition of exercise IDs in ModeJSON+* fixed processing of Null in EncoderJSON+* fixed rule ordering in function ruleset+ Changelog ideas-1.4 => ideas.1.5 * upgrade to ghc-7.10
ideas.cabal view
@@ -1,5 +1,5 @@ name: ideas-version: 1.5+version: 1.6 synopsis: Feedback services for intelligent tutoring systems homepage: http://ideas.cs.uu.nl/www/ description:@@ -63,17 +63,8 @@ wl-pprint Exposed-modules:- Ideas.Common.Algebra.Boolean- Ideas.Common.Algebra.BooleanLaws- Ideas.Common.Algebra.Field- Ideas.Common.Algebra.FieldLaws- Ideas.Common.Algebra.Group- Ideas.Common.Algebra.GroupLaws- Ideas.Common.Algebra.Law- Ideas.Common.Algebra.SmartGroup Ideas.Common.Classes Ideas.Common.Context- Ideas.Common.CyclicTree Ideas.Common.Derivation Ideas.Common.DerivationTree Ideas.Common.Environment@@ -92,7 +83,6 @@ Ideas.Common.Rewriting.Unification Ideas.Common.Rule Ideas.Common.Rule.Abstract- Ideas.Common.Rule.EnvironmentMonad Ideas.Common.Rule.Parameter Ideas.Common.Rule.Recognizer Ideas.Common.Rule.Transformation@@ -101,6 +91,7 @@ Ideas.Common.Strategy.Choice Ideas.Common.Strategy.Combinators Ideas.Common.Strategy.Configuration+ Ideas.Common.Strategy.CyclicTree Ideas.Common.Strategy.Derived Ideas.Common.Strategy.Legacy Ideas.Common.Strategy.Location@@ -114,11 +105,6 @@ Ideas.Common.Traversal.Navigator Ideas.Common.Traversal.Tests Ideas.Common.Traversal.Utils- Ideas.Common.Utils- Ideas.Common.Utils.QuickCheck- Ideas.Common.Utils.StringRef- Ideas.Common.Utils.TestSuite- Ideas.Common.Utils.Uniplate Ideas.Common.View Ideas.Encoding.DecoderJSON Ideas.Encoding.DecoderXML@@ -128,17 +114,17 @@ Ideas.Encoding.EncoderXML Ideas.Encoding.Evaluator Ideas.Encoding.LinkManager+ Ideas.Encoding.Logging Ideas.Encoding.ModeJSON Ideas.Encoding.ModeXML Ideas.Encoding.OpenMathSupport+ Ideas.Encoding.Options+ Ideas.Encoding.Request Ideas.Encoding.RulePresenter Ideas.Encoding.RulesInfo Ideas.Encoding.StrategyInfo- Ideas.Main.BlackBoxTests+ Ideas.Main.CmdLineOptions Ideas.Main.Default- Ideas.Main.Documentation- Ideas.Main.Logging- Ideas.Main.Options Ideas.Main.Revision Ideas.Service.BasicServices Ideas.Service.Diagnose@@ -149,13 +135,13 @@ Ideas.Service.FeedbackScript.Syntax Ideas.Service.FeedbackText Ideas.Service.ProblemDecomposition- Ideas.Service.Request Ideas.Service.ServiceList Ideas.Service.State Ideas.Service.Submit Ideas.Service.Types Ideas.Text.HTML Ideas.Text.JSON+ Ideas.Text.Latex Ideas.Text.OpenMath.Dictionary.Arith1 Ideas.Text.OpenMath.Dictionary.Calculus1 Ideas.Text.OpenMath.Dictionary.Fns1@@ -170,13 +156,20 @@ Ideas.Text.OpenMath.Object Ideas.Text.OpenMath.Symbol Ideas.Text.OpenMath.Tests- Ideas.Text.Parsing Ideas.Text.UTF8 Ideas.Text.XML Ideas.Text.XML.Document Ideas.Text.XML.Interface Ideas.Text.XML.Parser Ideas.Text.XML.Unicode+ Ideas.Utils.BlackBoxTests+ Ideas.Utils.Parsing+ Ideas.Utils.Prelude+ Ideas.Utils.QuickCheck+ Ideas.Utils.StringRef+ Ideas.Utils.TestSuite+ Ideas.Utils.Typeable+ Ideas.Utils.Uniplate --------------------------------------------------------------------------------
− src/Ideas/Common/Algebra/Boolean.hs
@@ -1,164 +0,0 @@-{-# LANGUAGE GeneralizedNewtypeDeriving #-} ------------------------------------------------------------------------------ --- Copyright 2016, Ideas project team. This file is distributed under the --- terms of the Apache License 2.0. For more information, see the files --- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution. ------------------------------------------------------------------------------ --- | --- Maintainer : bastiaan.heeren@ou.nl --- Stability : provisional --- Portability : portable (depends on ghc) --- ------------------------------------------------------------------------------ - -module Ideas.Common.Algebra.Boolean - ( -- * Boolean algebra - BoolValue(..), Boolean(..) - , ands, ors, implies, equivalent - -- * CoBoolean (matching) - , CoBoolean(..), conjunctions, disjunctions - -- * Monoids monoid - , DualMonoid(..), And(..), Or(..) - ) where - -import Control.Applicative -import Ideas.Common.Algebra.Group -import Ideas.Common.Classes -import Test.QuickCheck - --------------------------------------------------------- --- Boolean algebra - --- Minimal complete definitions: (true/false, or fromBool) and isTrue/isFalse -class BoolValue a where - true :: a - false :: a - fromBool :: Bool -> a - isTrue :: a -> Bool - isFalse :: a -> Bool - -- default definitions - true = fromBool True - false = fromBool False - fromBool b = if b then true else false - -class BoolValue a => Boolean a where - (<&&>) :: a -> a -> a - (<||>) :: a -> a -> a - complement :: a -> a - -instance BoolValue Bool where - fromBool = id - isTrue = id - isFalse = not - -instance BoolValue b => BoolValue (a -> b) where - fromBool x = const (fromBool x) - isTrue = error "not implemented" - isFalse = error "not implemented" - -instance Boolean Bool where - (<&&>) = (&&) - (<||>) = (||) - complement = not - -instance Boolean b => Boolean (a -> b) where - f <&&> g = \x -> f x <&&> g x - f <||> g = \x -> f x <||> g x - complement = (.) complement - -ands :: Boolean a => [a] -> a -- or use mconcat with And monoid -ands xs | null xs = true - | otherwise = foldr1 (<&&>) xs - -ors :: Boolean a => [a] -> a -ors xs | null xs = false - | otherwise = foldr1 (<||>) xs - -implies :: Boolean a => a -> a -> a -implies a b = complement a <||> b - -equivalent :: Boolean a => a -> a -> a -equivalent a b = (a <&&> b) <||> (complement a <&&> complement b) - --------------------------------------------------------- --- CoBoolean (matching) - -class BoolValue a => CoBoolean a where - isAnd :: a -> Maybe (a, a) - isOr :: a -> Maybe (a, a) - isComplement :: a -> Maybe a - -instance CoBoolean a => CoMonoid (And a) where - isEmpty = isTrue . fromAnd - isAppend = fmap (mapBoth And) . isAnd . fromAnd - -instance CoBoolean a => CoMonoidZero (And a) where - isMonoidZero = isFalse . fromAnd - -instance CoBoolean a => CoMonoid (Or a) where - isEmpty = isFalse . fromOr - isAppend = fmap (mapBoth Or) . isOr . fromOr - -instance CoBoolean a => CoMonoidZero (Or a) where - isMonoidZero = isTrue . fromOr - -conjunctions :: CoBoolean a => a -> [a] -conjunctions = map fromAnd . associativeList . And - -disjunctions :: CoBoolean a => a -> [a] -disjunctions = map fromOr . associativeList . Or - --------------------------------------------------------- --- Dual monoid for a monoid (and for or, and vice versa) - -class MonoidZero a => DualMonoid a where - (><) :: a -> a -> a - dualCompl :: a -> a - --------------------------------------------------------- --- And monoid - -newtype And a = And {fromAnd :: a} - deriving (Show, Eq, Ord, Arbitrary, CoArbitrary) - -instance Functor And where -- could be derived - fmap f = And . f . fromAnd - -instance Applicative And where - pure = And - And f <*> And a = And (f a) - -instance Boolean a => Monoid (And a) where - mempty = pure true - mappend = liftA2 (<&&>) - -instance Boolean a => MonoidZero (And a) where - mzero = pure false - -instance Boolean a => DualMonoid (And a) where - (><) = liftA2 (<||>) - dualCompl = liftA complement - --------------------------------------------------------- --- Or monoid - -newtype Or a = Or {fromOr :: a} - deriving (Show, Eq, Ord, Arbitrary, CoArbitrary) - -instance Functor Or where -- could be derived - fmap f = Or . f . fromOr - -instance Applicative Or where - pure = Or - Or f <*> Or a = Or (f a) - -instance Boolean a => Monoid (Or a) where - mempty = pure false - mappend = liftA2 (<||>) - -instance Boolean a => MonoidZero (Or a) where - mzero = pure true - -instance Boolean a => DualMonoid (Or a) where - (><) = liftA2 (<&&>) - dualCompl = liftA complement
− src/Ideas/Common/Algebra/BooleanLaws.hs
@@ -1,108 +0,0 @@------------------------------------------------------------------------------ --- Copyright 2016, Ideas project team. This file is distributed under the --- terms of the Apache License 2.0. For more information, see the files --- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution. ------------------------------------------------------------------------------ --- | --- Maintainer : bastiaan.heeren@ou.nl --- Stability : provisional --- Portability : portable (depends on ghc) --- ------------------------------------------------------------------------------ - -module Ideas.Common.Algebra.BooleanLaws - ( -- * Boolean laws - andOverOrLaws, orOverAndLaws - , complementAndLaws, complementOrLaws - , absorptionAndLaws, absorptionOrLaws - , deMorganAnd, deMorganOr - , doubleComplement, complementTrue, complementFalse - , booleanLaws - -- * Law transformer - , fromAndLaw, fromOrLaw - -- * Properties - , propsBoolean - ) where - -import Ideas.Common.Algebra.Boolean -import Ideas.Common.Algebra.Group -import Ideas.Common.Algebra.GroupLaws -import Ideas.Common.Algebra.Law -import Test.QuickCheck hiding ((><)) - --------------------------------------------------------- --- Boolean laws - -andOverOrLaws, orOverAndLaws :: Boolean a => [Law a] -andOverOrLaws = map fromAndLaw dualDistributive -orOverAndLaws = map fromOrLaw dualDistributive - -complementAndLaws, complementOrLaws :: Boolean a => [Law a] -complementAndLaws = map fromAndLaw dualComplement -complementOrLaws = map fromOrLaw dualComplement - -absorptionAndLaws, absorptionOrLaws :: Boolean a => [Law a] -absorptionAndLaws = map fromAndLaw dualAbsorption -absorptionOrLaws = map fromOrLaw dualAbsorption - -deMorganAnd, deMorganOr :: Boolean a => Law a -deMorganAnd = fromAndLaw deMorgan -deMorganOr = fromOrLaw deMorgan - -doubleComplement :: Boolean a => Law a -doubleComplement = law "double-complement" $ \a -> - complement (complement a) :==: a - -complementTrue, complementFalse :: Boolean a => Law a -complementTrue = fromAndLaw dualTrueFalse -complementFalse = fromOrLaw dualTrueFalse - -booleanLaws :: Boolean a => [Law a] -booleanLaws = - map fromAndLaw (idempotent : zeroLaws ++ commutativeMonoidLaws) ++ - map fromOrLaw (idempotent : zeroLaws ++ commutativeMonoidLaws) ++ - andOverOrLaws ++ orOverAndLaws ++ complementAndLaws ++ complementOrLaws ++ - absorptionAndLaws ++ absorptionOrLaws ++ - [deMorganAnd, deMorganOr, doubleComplement, complementTrue, complementFalse] - --------------------------------------------------------- --- Dual laws - -dualDistributive :: DualMonoid a => [Law a] -dualDistributive = - [leftDistributiveFor (<>) (><), rightDistributiveFor (<>) (><)] - -dualAbsorption :: DualMonoid a => [Law a] -dualAbsorption = - [ law "absorption" $ \a b -> a `f` (a `g` b) :==: a - | f <- [(<>), flip (<>)] - , g <- [(><), flip (><)] - ] - -dualComplement :: DualMonoid a => [Law a] -dualComplement = - [ law "complement" $ \a -> dualCompl a <> a :==: mzero - , law "complement" $ \a -> a <> dualCompl a :==: mzero - ] - -dualTrueFalse :: DualMonoid a => Law a -dualTrueFalse = law "true-false" $ dualCompl mempty :==: mzero - -deMorgan :: DualMonoid a => Law a -deMorgan = law "demorgan" $ \a b -> - dualCompl (a <> b) :==: dualCompl a >< dualCompl b - --------------------------------------------------------- --- And laws - -fromAndLaw :: Law (And a) -> Law a -fromAndLaw = mapLaw And fromAnd - -fromOrLaw :: Law (Or a) -> Law a -fromOrLaw = mapLaw Or fromOr - --------------------------------------------------------- --- Tests for Bool instance - -propsBoolean :: [Property] -propsBoolean = map property (booleanLaws :: [Law Bool])
− src/Ideas/Common/Algebra/Field.hs
@@ -1,237 +0,0 @@-{-# LANGUAGE GeneralizedNewtypeDeriving #-} ------------------------------------------------------------------------------ --- Copyright 2016, Ideas project team. This file is distributed under the --- terms of the Apache License 2.0. For more information, see the files --- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution. ------------------------------------------------------------------------------ --- | --- Maintainer : bastiaan.heeren@ou.nl --- Stability : provisional --- Portability : portable (depends on ghc) --- ------------------------------------------------------------------------------ - -module Ideas.Common.Algebra.Field - ( -- * Semi-ring - SemiRing(..) - -- * Ring - , Ring(..) - -- * Field - , Field(..) - -- * Additive monoid - , Additive(..) - -- * Multiplicative monoid - , Multiplicative(..) - -- * Datatype for safe numeric operators - , SafeNum, safeNum - -- * CoSemiRing, CoRing, and CoField (for matching) - , CoSemiRing(..), CoRing(..), CoField(..) - ) where - -import Control.Monad -import Ideas.Common.Algebra.Group -import Ideas.Common.Classes (mapBoth) -import Test.QuickCheck -import qualified Control.Applicative as A -import qualified Control.Applicative as Applicative - --------------------------------------------------------- --- Semi-ring - -infixl 6 |+| -infixl 7 |*| - -class SemiRing a where - -- additive - (|+|) :: a -> a -> a - zero :: a - sum :: [a] -> a - -- multiplicative - (|*|) :: a -> a -> a - one :: a - product :: [a] -> a - -- default implementation - sum [] = zero - sum xs = foldl1 (|+|) xs - product [] = one - product xs = foldl1 (|*|) xs - --------------------------------------------------------- --- Ring - -infixl 6 |-| - --- Minimal complete definition: plusInverse or <-> -class SemiRing a => Ring a where - plusInverse :: a -> a - (|-|) :: a -> a -> a - -- default definitions - plusInverse = (zero |-|) - a |-| b = a |+| plusInverse b - --------------------------------------------------------- --- Field - -infixl 7 |/| - --- Minimal complete definition: mulInverse or </> -class Ring a => Field a where - timesInverse :: a -> a - (|/|) :: a -> a -> a - -- default definitions - timesInverse = (one |/|) - a |/| b = a |*| timesInverse b - --------------------------------------------------------- --- Additive monoid - -newtype Additive a = Additive {fromAdditive :: a} - deriving (Show, Eq, Ord, Arbitrary, CoArbitrary) - -instance Functor Additive where -- could be derived - fmap f = Additive . f . fromAdditive - -instance A.Applicative Additive where - pure = Additive - Additive f <*> Additive a = Additive (f a) - -instance SemiRing a => Monoid (Additive a) where - mempty = A.pure zero - mappend = A.liftA2 (|+|) - -instance Ring a => Group (Additive a) where - inverse = A.liftA plusInverse - appendInv = A.liftA2 (|-|) - --------------------------------------------------------- --- Multiplicative monoid - -newtype Multiplicative a = Multiplicative {fromMultiplicative :: a} - deriving (Show, Eq, Ord, Arbitrary, CoArbitrary) - -instance Functor Multiplicative where -- could be derived - fmap f = Multiplicative . f . fromMultiplicative - -instance A.Applicative Multiplicative where - pure = Multiplicative - Multiplicative f <*> Multiplicative a = Multiplicative (f a) - -instance SemiRing a => Monoid (Multiplicative a) where - mempty = A.pure one - mappend = A.liftA2 (|*|) - -instance Field a => Group (Multiplicative a) where - inverse = A.liftA timesInverse - appendInv = A.liftA2 (|/|) - -instance SemiRing a => MonoidZero (Multiplicative a) where - mzero = Multiplicative zero - --------------------------------------------------------- --- Datatype for safe numeric operators - -data SafeNum a = Ok a | Exception String - -safeNum :: SafeNum a -> Either String a -safeNum (Ok a) = Right a -safeNum (Exception s) = Left s - -instance Arbitrary a => Arbitrary (SafeNum a) where - arbitrary = liftM return arbitrary - -instance Eq a => Eq (SafeNum a) where - Ok a == Ok b = a == b - _ == _ = True - -instance Ord a => Ord (SafeNum a) where - Ok a `compare` Ok b = a `compare` b - _ `compare` _ = EQ - -instance Show a => Show (SafeNum a) where - show = either ("Exception: " ++) show . safeNum - -instance Functor SafeNum where - fmap f = either Exception (return . f) . safeNum - -instance Applicative.Applicative SafeNum where - pure = return - (<*>) = ap - -instance Monad SafeNum where - return = Ok - fail = Exception - m >>= f = either Exception f (safeNum m) - -instance Num a => Num (SafeNum a) where - (+) = liftM2 (+) - (*) = liftM2 (*) - (-) = liftM2 (-) - negate = liftM negate - abs = liftM abs - signum = liftM signum - fromInteger = return . fromInteger - -instance (Eq a, Fractional a) => Fractional (SafeNum a) where - a / b = liftM2 (/) a (safeDivisor b) - recip = liftM recip . safeDivisor - fromRational = return . fromRational - -instance Num a => SemiRing (SafeNum a) where - (|+|) = (+) - (|*|) = (*) - zero = 0 - one = 1 - -instance Num a => Ring (SafeNum a) where - plusInverse = negate - (|-|) = (-) - -instance (Eq a, Fractional a) => Field (SafeNum a) where - timesInverse = recip - (|/|) = (/) - -safeDivisor :: (Eq a, Num a) => SafeNum a -> SafeNum a -safeDivisor m = m >>= \a -> - if a == 0 then fail "division by zero" else return a - ------------------------------------------------------------- - -class CoSemiRing a where - -- additive - isPlus :: a -> Maybe (a, a) - isZero :: a -> Bool - -- multiplicative - isTimes :: a -> Maybe (a, a) - isOne :: a -> Bool - --- Minimal complete definition: plusInverse or <-> -class CoSemiRing a => CoRing a where - isNegate :: a -> Maybe a - isMinus :: a -> Maybe (a, a) - -- default definition - isMinus _ = Nothing - -class CoRing a => CoField a where - isRecip :: a -> Maybe a - isDivision :: a -> Maybe (a, a) - -- default definition - isDivision _ = Nothing - -instance CoSemiRing a => CoMonoid (Additive a) where - isEmpty = isZero . fromAdditive - isAppend = fmap (mapBoth Additive) . isPlus . fromAdditive - -instance CoRing a => CoGroup (Additive a) where - isInverse = fmap Additive . isNegate . fromAdditive - isAppendInv = fmap (mapBoth Additive) . isMinus . fromAdditive - -instance CoSemiRing a => CoMonoid (Multiplicative a) where - isEmpty = isOne . fromMultiplicative - isAppend = fmap (mapBoth Multiplicative) . isTimes . fromMultiplicative - -instance CoField a => CoGroup (Multiplicative a) where - isInverse = fmap Multiplicative . isRecip . fromMultiplicative - isAppendInv = fmap (mapBoth Multiplicative) . isDivision . fromMultiplicative - -instance CoSemiRing a => CoMonoidZero (Multiplicative a) where - isMonoidZero = isZero . fromMultiplicative
− src/Ideas/Common/Algebra/FieldLaws.hs
@@ -1,111 +0,0 @@------------------------------------------------------------------------------ --- Copyright 2016, Ideas project team. This file is distributed under the --- terms of the Apache License 2.0. For more information, see the files --- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution. ------------------------------------------------------------------------------ --- | --- Maintainer : bastiaan.heeren@ou.nl --- Stability : provisional --- Portability : portable (depends on ghc) --- ------------------------------------------------------------------------------ - -module Ideas.Common.Algebra.FieldLaws - ( -- * Semi-ring laws - leftDistributive, rightDistributive - , distributiveLaws, semiRingLaws - -- * Ring laws - , leftNegateTimes, rightNegateTimes - , negateTimesLaws, ringLaws, commutativeRingLaws - , distributiveSubtractionLaws - -- * Field laws - , exchangeInverses, fieldLaws - -- * Laws for additive monoid - , fromAdditiveLaw - -- * Laws for multiplicative monoid - , fromMultiplicativeLaw - -- * Properties - , propsField - ) where - -import Ideas.Common.Algebra.Field -import Ideas.Common.Algebra.GroupLaws -import Ideas.Common.Algebra.Law -import Test.QuickCheck - --------------------------------------------------------- --- Semi-ring laws - -leftDistributive :: SemiRing a => Law a -leftDistributive = leftDistributiveFor (|*|) (|+|) - -rightDistributive :: SemiRing a => Law a -rightDistributive = rightDistributiveFor (|*|) (|+|) - -distributiveLaws :: SemiRing a => [Law a] -distributiveLaws = [leftDistributive, rightDistributive] - -semiRingLaws :: SemiRing a => [Law a] -semiRingLaws = - map fromAdditiveLaw commutativeMonoidLaws ++ - map fromMultiplicativeLaw monoidZeroLaws ++ - distributiveLaws - --------------------------------------------------------- --- Ring laws - -leftNegateTimes :: Ring a => Law a -leftNegateTimes = law "left-negate-times" $ \a b -> - plusInverse a |*| b :==: plusInverse (a |*| b) - -rightNegateTimes :: Ring a => Law a -rightNegateTimes = law "right-negate-times" $ \a b -> - a |*| plusInverse b :==: plusInverse (a |*| b) - -negateTimesLaws :: Ring a => [Law a] -negateTimesLaws = [leftNegateTimes, rightNegateTimes] - -ringLaws :: Ring a => [Law a] -ringLaws = - map fromAdditiveLaw abelianGroupLaws ++ - map fromMultiplicativeLaw monoidZeroLaws ++ - distributiveLaws ++ negateTimesLaws - -commutativeRingLaws :: Ring a => [Law a] -commutativeRingLaws = - fromMultiplicativeLaw commutative : ringLaws - -distributiveSubtractionLaws :: Ring a => [Law a] -distributiveSubtractionLaws = - [leftDistributiveFor (|*|) (|-|), rightDistributiveFor (|*|) (|-|)] - --------------------------------------------------------- --- Field laws - -exchangeInverses :: Field a => Law a -exchangeInverses = law "exchange-inverses" $ \a -> - timesInverse (plusInverse a) :==: plusInverse (timesInverse a) - -fieldLaws :: Field a => [Law a] -fieldLaws = - map fromAdditiveLaw abelianGroupLaws ++ - map fromMultiplicativeLaw abelianGroupLaws ++ - distributiveLaws ++ negateTimesLaws ++ [exchangeInverses] - --------------------------------------------------------- --- Laws for additive monoid - -fromAdditiveLaw :: Law (Additive a) -> Law a -fromAdditiveLaw = mapLaw Additive fromAdditive - --------------------------------------------------------- --- Laws for multiplicative monoid - -fromMultiplicativeLaw :: Law (Multiplicative a) -> Law a -fromMultiplicativeLaw = mapLaw Multiplicative fromMultiplicative - --------------------------------------------------------- --- Properties - -propsField :: [Property] -propsField = map property (fieldLaws :: [Law (SafeNum Rational)])
− src/Ideas/Common/Algebra/Group.hs
@@ -1,196 +0,0 @@-{-# LANGUAGE GeneralizedNewtypeDeriving #-} ------------------------------------------------------------------------------ --- Copyright 2016, Ideas project team. This file is distributed under the --- terms of the Apache License 2.0. For more information, see the files --- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution. ------------------------------------------------------------------------------ --- | --- Maintainer : bastiaan.heeren@ou.nl --- Stability : provisional --- Portability : portable (depends on ghc) --- ------------------------------------------------------------------------------ - -module Ideas.Common.Algebra.Group - ( -- * Monoids - Monoid(..), (<>) - -- * Groups - , Group(..), (<>-) - -- * Monoids with a zero element - , MonoidZero(..), WithZero, fromWithZero - -- * CoMonoid, CoGroup, and CoMonoidZero (for matching) - , CoMonoid(..), CoGroup(..), CoMonoidZero(..) - , associativeList - ) where - -import Control.Applicative -import Control.Monad (liftM2) -import Data.Maybe -import Data.Monoid -import Ideas.Common.Classes -import qualified Data.Set as S - --------------------------------------------------------- --- Groups - --- | Minimal complete definition: inverse or appendInverse -class Monoid a => Group a where - inverse :: a -> a - appendInv :: a -> a -> a - -- default definitions - inverse = (mempty <>-) - appendInv a b = a <> inverse b - -infixl 6 <>- - -(<>-) :: Group a => a -> a -> a -(<>-) = appendInv - --------------------------------------------------------- --- Monoids with a zero element --- This element could be the additive identity from a (semi-)ring for --- the multiplicative monoid - -class Monoid a => MonoidZero a where - mzero :: a - --- Type that adds a zero element -newtype WithZero a = WZ { fromWithZero :: Maybe a } - deriving (Eq, Ord, Functor, Foldable, Applicative) - -instance Monoid a => Monoid (WithZero a) where - mempty = WZ (Just mempty) - mappend x y = WZ (liftM2 mappend (fromWithZero x) (fromWithZero y)) - -instance Monoid a => MonoidZero (WithZero a) where - mzero = WZ Nothing - -instance Traversable WithZero where - traverse f = liftA WZ . traverse f . fromWithZero - --------------------------------------------------------- --- Groups - -class CoMonoid a where - isEmpty :: a -> Bool - isAppend :: a -> Maybe (a, a) - -class CoMonoid a => CoGroup a where - isInverse :: a -> Maybe a - isAppendInv :: a -> Maybe (a, a) - -- default definition - isAppendInv = const Nothing - -class CoMonoid a => CoMonoidZero a where - isMonoidZero :: a -> Bool - -fromSemiGroup :: (CoMonoid a, Monoid b) => (a -> b) -> a -> b -fromSemiGroup f = rec - where - rec a = maybe (f a) make (isAppend a) - make (x, y) = rec x <> rec y -{- -fromMonoid :: (CoMonoid a, Monoid b) => (a -> b) -> a -> b -fromMonoid f = fromSemiGroup $ \a -> - if isEmpty a then mempty else f a - -fromGroup :: (CoGroup a, Group b) => (a -> b) -> a -> b -fromGroup f = rec - where - rec = fromMonoid $ \a -> - case isInverse a of - Just x -> inverse (rec x) - Nothing -> - case isAppendInverse a of - Just (x, y) -> rec x <>- rec y - Nothing -> f a - -fromMonoidZero :: (CoMonoidZero a, MonoidZero b) => (a -> b) -> a -> b -fromMonoidZero f = fromMonoid $ \a -> - if isZero a then zero else f a - ----------------------- --} -associativeList :: CoMonoid a => a -> [a] -associativeList = fromSemiGroup singleton -{- -monoidList :: CoMonoid a => a -> [a] -monoidList = fromMonoid singleton - --- For commutative (and associative) monoids -monoidMultiSet :: (CoMonoid a, Ord a) => a -> MultiSet a -monoidMultiSet = fromMonoid singleton - --- For associative, commutative, idempotent (ACI) monoids -monoidSet :: (CoMonoid a, Ord a) => a -> S.Set a -monoidSet = fromMonoid singleton - -groupSequence :: (CoGroup a, Eq a) => a -> GroupSequence a -groupSequence = fromGroup singleton - -abelianMultiSet :: (CoGroup a, Ord a) => a -> MultiSet a -abelianMultiSet = fromGroup singleton - -monoidZeroList :: CoMonoidZero a => a -> WithZero [a] -monoidZeroList = fromMonoidZero (pure . singleton) - ----------------------- - -newtype MultiSet a = MS (M.Map a Int) - -instance Collection MultiSet where - singleton a = MS (M.singleton a 1) - -instance Ord a => Monoid (MultiSet a) where - mempty = MS mempty - mappend (MS m1) (MS m2) = MS (M.unionWith (+) m1 m2) - -instance Ord a => Group (MultiSet a) where - inverse (MS m) = MS (fmap negate m) - ----------------------- - -newtype GroupSequence a = GS (Q.Seq (a, Bool)) - -instance Collection GroupSequence where - singleton a = GS (Q.singleton (a, False)) - -instance Eq a => Monoid (GroupSequence a) where - mempty = GS mempty - mappend (GS xs) (GS ys) = - case (Q.viewr xs, Q.viewl ys) of - (as Q.:> (a, ai), (b, bi) Q.:< bs) | a == b && ai /= bi -> - mappend (GS as) (GS bs) - _ -> GS (xs <> ys) - -instance Eq a => Group (GroupSequence a) where - inverse (GS xs) = GS (fmap (second not) xs) -- actually: reverse order!! --} ----------------------- - -instance CoMonoid [a] where - isEmpty = null - isAppend (x:xs@(_:_)) = Just ([x], xs) - isAppend _ = Nothing - -instance CoMonoid (S.Set a) where - isEmpty = S.null - isAppend s - | S.size s > 1 = Just (mapFirst S.singleton (S.deleteFindMin s)) - | otherwise = Nothing - -{- -instance CoMonoid (Q.Seq a) where - isEmpty = Q.null - isAppend xs - | n > 1 = Just (Q.splitAt (n `div` 2) xs) - | otherwise = Nothing - where - n = Q.length xs --} -instance CoMonoid a => CoMonoid (WithZero a) where - isEmpty = maybe False isEmpty . fromWithZero - isAppend a = fromWithZero a >>= fmap (mapBoth pure) . isAppend - -instance CoMonoid a => CoMonoidZero (WithZero a) where - isMonoidZero = isNothing . fromWithZero
− src/Ideas/Common/Algebra/GroupLaws.hs
@@ -1,150 +0,0 @@------------------------------------------------------------------------------ --- Copyright 2016, Ideas project team. This file is distributed under the --- terms of the Apache License 2.0. For more information, see the files --- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution. ------------------------------------------------------------------------------ --- | --- Maintainer : bastiaan.heeren@ou.nl --- Stability : provisional --- Portability : portable (depends on ghc) --- ------------------------------------------------------------------------------ - -module Ideas.Common.Algebra.GroupLaws - ( -- * Monoid laws - associative, leftIdentity - , rightIdentity, identityLaws, monoidLaws, commutativeMonoidLaws - , idempotent - -- * Group laws - , leftInverse, rightInverse, doubleInverse - , inverseIdentity, inverseDistrFlipped, inverseLaws, groupLaws - , appendInverseLaws - -- * Abelian group laws - , commutative, inverseDistr, abelianGroupLaws - -- * Laws for monoids with a zero element - , leftZero, rightZero, zeroLaws, monoidZeroLaws - -- * Generalized laws - , associativeFor, commutativeFor, idempotentFor - , leftDistributiveFor, rightDistributiveFor - ) where - -import Ideas.Common.Algebra.Group -import Ideas.Common.Algebra.Law -import Prelude hiding ((<*>)) - --------------------------------------------------------- --- Monoids - -associative :: Monoid a => Law a -associative = associativeFor (<>) - -leftIdentity :: Monoid a => Law a -leftIdentity = law "left-identity" $ \a -> mempty <> a :==: a - -rightIdentity :: Monoid a => Law a -rightIdentity = law "right-identity" $ \a -> a <> mempty :==: a - -identityLaws :: Monoid a => [Law a] -identityLaws = [leftIdentity, rightIdentity] - -monoidLaws :: Monoid a => [Law a] -monoidLaws = associative : identityLaws - -commutativeMonoidLaws :: Monoid a => [Law a] -commutativeMonoidLaws = monoidLaws ++ [commutative] - --- | Not all monoids are idempotent (see: idempotentFor) -idempotent :: Monoid a => Law a -idempotent = idempotentFor (<>) - --------------------------------------------------------- --- Groups - -leftInverse :: Group a => Law a -leftInverse = law "left-inverse" $ \a -> inverse a <> a :==: mempty - -rightInverse :: Group a => Law a -rightInverse = law "right-inverse" $ \a -> a <> inverse a :==: mempty - -doubleInverse :: Group a => Law a -doubleInverse = law "double-inverse" $ \a -> inverse (inverse a) :==: a - -inverseIdentity :: Group a => Law a -inverseIdentity = law "inverse-identity" $ inverse mempty :==: mempty - -inverseDistrFlipped :: Group a => Law a -inverseDistrFlipped = law "inverse-distr-flipped" $ \a b -> - inverse (a <> b) :==: inverse b <> inverse a - -inverseLaws :: Group a => [Law a] -inverseLaws = [leftInverse, rightInverse] - -groupLaws :: Group a => [Law a] -groupLaws = monoidLaws ++ inverseLaws ++ - [doubleInverse, inverseIdentity, inverseDistrFlipped] - -appendInverseLaws :: Group a => [Law a] -appendInverseLaws = - [ make 1 $ \a b -> a <>- b :==: a <> inverse b - , make 2 $ \a -> a <>- a :==: mempty - , make 3 $ \a -> a <>- mempty :==: a - , make 4 $ \a -> mempty <>- a :==: inverse a - , make 5 $ \a b c -> a <>- (b <> c) :==: (a <>- b) <>- c - , make 6 $ \a b c -> a <>- (b <>- c) :==: (a <>- b) <> c - , make 7 $ \a b c -> a <> (b <>- c) :==: (a <> b) <>- c - , make 8 $ \a b -> a <>- inverse b :==: a <> b - , make 9 $ \a b -> inverse (a <>- b) :==: inverse a <> b - ] - where - make n = law ("append-inverse-law" ++ show (n :: Int)) - --------------------------------------------------------- --- Abelian groups - -commutative :: Monoid a => Law a -commutative = commutativeFor (<>) - -inverseDistr :: Group a => Law a -inverseDistr = law "inverse-distr" $ \a b -> - inverse (a <> b) :==: (inverse a <> inverse b) - -abelianGroupLaws :: Group a => [Law a] -abelianGroupLaws = groupLaws ++ [commutative, inverseDistr] - --------------------------------------------------------- --- Monoids with a zero element --- This element could be the additive identity from a (semi-)ring for --- the multiplicative monoid - -leftZero :: MonoidZero a => Law a -leftZero = law "left-zero" $ \a -> mzero <> a :==: mzero - -rightZero:: MonoidZero a => Law a -rightZero = law "right-zero" $ \a -> a <> mzero :==: mzero - -zeroLaws :: MonoidZero a => [Law a] -zeroLaws = [leftZero, rightZero] - -monoidZeroLaws :: MonoidZero a => [Law a] -monoidZeroLaws = monoidLaws ++ zeroLaws - --------------------------------------------------------- --- Generalized laws - -associativeFor :: (a -> a -> a) -> Law a -associativeFor (?) = law "associative" $ \a b c -> - a ? (b ? c) :==: (a ? b) ? c - -commutativeFor :: (a -> a -> a) -> Law a -commutativeFor (?) = law "commutative" $ \a b -> a ? b :==: b ? a - -idempotentFor :: (a -> a -> a) -> Law a -idempotentFor (?) = law "idempotent" $ \a -> a ? a :==: a - -leftDistributiveFor :: (a -> a -> a) -> (a -> a -> a) -> Law a -leftDistributiveFor (<*>) (<+>) = law "left-distributive" $ \a b c -> - a <*> (b <+> c) :==: (a <*> b) <+> (a <*> c) - -rightDistributiveFor :: (a -> a -> a) -> (a -> a -> a) -> Law a -rightDistributiveFor (<*>) (<+>) = law "right-distributive" $ \a b c -> - (a <+> b) <*> c :==: (a <*> c) <+> (b <*> c)
− src/Ideas/Common/Algebra/Law.hs
@@ -1,78 +0,0 @@-{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, ExistentialQuantification #-} ------------------------------------------------------------------------------ --- Copyright 2016, Ideas project team. This file is distributed under the --- terms of the Apache License 2.0. For more information, see the files --- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution. ------------------------------------------------------------------------------ --- | --- Maintainer : bastiaan.heeren@ou.nl --- Stability : provisional --- Portability : portable (depends on ghc) --- ------------------------------------------------------------------------------ - -module Ideas.Common.Algebra.Law - ( Law, LawSpec((:==:)), law, lawAbs, mapLaw - , propertyLaw, rewriteLaw - ) where - -import Ideas.Common.Rewriting -import Test.QuickCheck - -infix 1 :==: - -data Law a = Law String (LawSpec a) - -instance Show (Law a) where - show (Law s _) = s - -data LawSpec a - = AbsMono (a -> LawSpec a) -- simple abstraction (fewer classes needed) - | forall b . (Arbitrary b, Show b, Different b) => Abs (b -> LawSpec a) -- generalized abstraction - | a :==: a - -law :: LawBuilder l a => String -> l -> Law a -law s l = Law s (lawSpec l) - -lawAbs :: (Different b, Arbitrary b, Show b) => (b -> LawSpec a) -> LawSpec a -lawAbs = Abs - -class LawBuilder l a | l -> a where - lawSpec :: l -> LawSpec a - -instance LawBuilder (LawSpec a) a where - lawSpec = id - -instance LawBuilder (Law a) a where - lawSpec = getLawSpec - -instance LawBuilder b a => LawBuilder (a -> b) a where - lawSpec f = AbsMono (lawSpec . f) - -instance (Show a, Eq a, Arbitrary a) => Testable (Law a) where - property = propertyLaw (==) - -mapLaw :: (b -> a) -> (a -> b) -> Law a -> Law b -mapLaw to from (Law s l) = Law s (rec l) - where - rec (AbsMono f) = AbsMono (rec . f . to) - rec (Abs f) = Abs (rec . f) - rec (a :==: b) = from a :==: from b - -propertyLaw :: (Arbitrary a, Show a, Testable b) => (a -> a -> b) -> Law a -> Property -propertyLaw eq = rec . getLawSpec - where - rec (AbsMono f) = property (rec . f) - rec (Abs f) = property (rec . f) - rec (a :==: b) = property (eq a b) - -rewriteLaw :: (Different a, IsTerm a, Arbitrary a, Show a) => Law a -> RewriteRule a -rewriteLaw (Law s l) = makeRewriteRule s l - -instance (Arbitrary a, IsTerm a, Show a, Different a) => RuleBuilder (LawSpec a) a where - buildRuleSpec i (a :==: b) = buildRuleSpec i (a :~> b) - buildRuleSpec i (AbsMono f) = buildRuleSpec i f - buildRuleSpec i (Abs f) = buildRuleSpec i f - -getLawSpec :: Law a -> LawSpec a -getLawSpec (Law _ l) = l
− src/Ideas/Common/Algebra/SmartGroup.hs
@@ -1,198 +0,0 @@-{-# LANGUAGE GeneralizedNewtypeDeriving, PatternGuards #-} ------------------------------------------------------------------------------ --- Copyright 2016, Ideas project team. This file is distributed under the --- terms of the Apache License 2.0. For more information, see the files --- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution. ------------------------------------------------------------------------------ --- | --- Maintainer : bastiaan.heeren@ou.nl --- Stability : provisional --- Portability : portable (depends on ghc) --- ------------------------------------------------------------------------------ - -module Ideas.Common.Algebra.SmartGroup - ( -- * Smart datatypes - Smart(..), SmartZero(..), SmartGroup(..) - --- * Smart field - , SmartField(..), (.+.), (.-.), neg, (.*.), (./.) - -- * Smart booleans - , (.&&.), (.||.) - ) where - -import Control.Applicative -import Control.Monad (mplus) -import Data.Maybe -import Ideas.Common.Algebra.Boolean -import Ideas.Common.Algebra.Field -import Ideas.Common.Algebra.Group - -newtype Smart a = Smart {fromSmart :: a} - deriving (Show, Eq, Ord, CoMonoid, MonoidZero, CoMonoidZero) - -instance Functor Smart where -- could be derived - fmap f = Smart . f . fromSmart - -instance Applicative Smart where - pure = Smart - Smart f <*> Smart a = Smart (f a) - -instance (CoMonoid a, Monoid a) => Monoid (Smart a) where - mempty = Smart mempty - mappend a b - | isEmpty a = b - | isEmpty b = a - | otherwise = liftA2 (<>) a b - --------------------------------------------------------------- - -newtype SmartZero a = SmartZero {fromSmartZero :: a} - deriving (Show, Eq, Ord, MonoidZero, CoMonoid, CoMonoidZero) - -instance Functor SmartZero where -- could be derived - fmap f = SmartZero . f . fromSmartZero - -instance Applicative SmartZero where - pure = SmartZero - SmartZero f <*> SmartZero a = SmartZero (f a) - -instance (CoMonoidZero a, MonoidZero a) => Monoid (SmartZero a) where - mempty = SmartZero mempty - mappend a b - | isMonoidZero a || isMonoidZero b = mzero - | otherwise = liftA2 (<>) a b - --------------------------------------------------------------- - -newtype SmartGroup a = SmartGroup {fromSmartGroup :: a} - deriving (Show, Eq, Ord, CoMonoid, CoGroup, CoMonoidZero, MonoidZero) - -instance Functor SmartGroup where -- could be derived - fmap f = SmartGroup . f . fromSmartGroup - -instance Applicative SmartGroup where - pure = SmartGroup - SmartGroup f <*> SmartGroup a = SmartGroup (f a) - -instance (CoGroup a, Group a) => Monoid (SmartGroup a) where - mempty = SmartGroup mempty - mappend a b - | isEmpty a = b - | otherwise = fromMaybe (liftA2 (<>) a b) (matchGroup alg b) - where - alg = (a, \x y -> (a <> x) <> y, \x -> a <>- x, \x y -> (a <> x) <>- y) - -instance (CoGroup a, Group a) => Group (SmartGroup a) where - inverse a = fromMaybe (liftA inverse a) (matchGroup alg a) - where - alg = (mempty, \x y -> inverse x <>- y, id, \x y -> inverse x <> y) - appendInv a b - | isEmpty a = inverse b - | otherwise = fromMaybe (liftA2 (<>-) a b) (matchGroup alg b) - where - alg = (a, \x y -> (a <>- x) <>- y, \x -> a <> x, \x y -> (a <>- x) <> y) - --------------------------------------------------------------- - -type GroupMatch a b = (b, a -> a -> b, a -> b, a -> a -> b) - -matchGroup :: CoGroup a => GroupMatch a b -> a -> Maybe b -matchGroup (emp, app, inv, appinv) a = - (if isEmpty a then Just emp else Nothing) `mplus` - fmap (uncurry app) (isAppend a) `mplus` - fmap inv (isInverse a) `mplus` - fmap (uncurry appinv) (isAppendInv a) - --------------------------------------------------------------- --- Smart Field - -newtype SmartField a = SmartField {fromSmartField :: a} - deriving (CoSemiRing, CoRing, CoField) - -instance Functor SmartField where -- could be derived - fmap f = SmartField . f . fromSmartField - -instance Applicative SmartField where - pure = SmartField - SmartField f <*> SmartField a = SmartField (f a) - -instance (CoField a, Field a) => SemiRing (SmartField a) where - zero = SmartField zero - one = SmartField one - SmartField a |+| SmartField b = SmartField $ fromAdditive $ fromSmartGroup $ - SmartGroup (Additive a) <> SmartGroup (Additive b) - a |*| b - | Just x <- isNegate a = plusInverse (x |*| b) - | Just x <- isNegate b = plusInverse (a |*| x) - | isZero a || isZero b = zero - | isOne a = b - | isOne b = a - | Just (x, y) <- isTimes b = (a |*| x) |*| y - | Just (x, y) <- isDivision b = (a |*| x) |/| y - | otherwise = liftA2 (|*|) a b - -instance (CoField a, Field a) => Ring (SmartField a) where - plusInverse = SmartField . fromAdditive . fromSmartGroup . inverse - . SmartGroup . Additive . fromSmartField - SmartField a |-| SmartField b = SmartField $ fromAdditive $ fromSmartGroup $ - SmartGroup (Additive a) <>- SmartGroup (Additive b) - -instance (CoField a, Field a) => Field (SmartField a) where - timesInverse a - | Just x <- isNegate a = plusInverse (timesInverse x) - | Just (x, y) <- isDivision a, isOne y = x - | otherwise = liftA timesInverse a - a |/| b - | Just x <- isNegate a = plusInverse (x |/| b) - | Just x <- isNegate b = plusInverse (a |/| x) - | isOne b = a - | Just (x, y) <- isDivision a = x |/| (y |*| b) - | otherwise = liftA2 (|/|) a b - ------------------------------------------------------------------- - -infixl 7 .*., ./. -infixl 6 .-., .+. - -(.+.) :: (CoField a, Field a) => a -> a -> a -a .+. b = fromSmartField $ SmartField a |+| SmartField b - -(.-.) :: (CoField a, Field a) => a -> a -> a -a .-. b = fromSmartField $ SmartField a |-| SmartField b - -neg :: (CoField a, Field a) => a -> a -neg = fromSmartField . plusInverse . SmartField - -(.*.) :: (CoField a, Field a) => a -> a -> a -a .*. b = fromSmartField $ SmartField a |*| SmartField b - -(./.) :: (CoField a, Field a) => a -> a -> a -a ./. b = fromSmartField $ SmartField a |/| SmartField b - --- myrecip :: (CoField a, Field a) => a -> a --- myrecip = fromSmartField . timesInverse . SmartField - --------------------------------------------------------------- --- Smart booleans - -instance BoolValue a => BoolValue (Smart a) where - fromBool = Smart . fromBool - isTrue = isTrue . fromSmart - isFalse = isFalse . fromSmart - -instance (Boolean a, CoBoolean a) => Boolean (Smart a) where - a <&&> b = fmap fromAnd $ fromSmartZero $ - SmartZero (fmap And a) <> SmartZero (fmap And b) - a <||> b = fmap fromOr $ fromSmartZero $ - SmartZero (fmap Or a) <> SmartZero (fmap Or b) - complement (Smart a) - | isTrue a = false - | isFalse a = true - | otherwise = Smart $ fromMaybe (complement a) (isComplement a) - -infixr 4 .||. -infixr 5 .&&. - -(.&&.), (.||.) :: (Boolean a, CoBoolean a) => a -> a -> a -a .&&. b = fromSmart $ Smart a <&&> Smart b -a .||. b = fromSmart $ Smart a <||> Smart b
src/Ideas/Common/Classes.hs view
@@ -23,6 +23,9 @@ , BiFunctor(biMap, mapFirst, mapSecond), mapBoth -- * Type class Fix , Fix(..) + -- * Boolean Algebra + , BoolValue(..), Boolean(..) + , ands, ors, implies, equivalent -- * Buggy and Minor properties , Buggy(..), Minor(..) ) where @@ -120,6 +123,60 @@ fix :: (a -> a) -> a -- default implementation fix f = let a = f a in a + +-------------------------------------------------------- +-- Boolean algebra + +-- Minimal complete definitions: (true/false, or fromBool) and isTrue/isFalse +class BoolValue a where + true :: a + false :: a + fromBool :: Bool -> a + isTrue :: a -> Bool + isFalse :: a -> Bool + -- default definitions + true = fromBool True + false = fromBool False + fromBool b = if b then true else false + +class BoolValue a => Boolean a where + (<&&>) :: a -> a -> a + (<||>) :: a -> a -> a + complement :: a -> a + +instance BoolValue Bool where + fromBool = id + isTrue = id + isFalse = not + +instance BoolValue b => BoolValue (a -> b) where + fromBool x = const (fromBool x) + isTrue = error "not implemented" + isFalse = error "not implemented" + +instance Boolean Bool where + (<&&>) = (&&) + (<||>) = (||) + complement = not + +instance Boolean b => Boolean (a -> b) where + f <&&> g = \x -> f x <&&> g x + f <||> g = \x -> f x <||> g x + complement = (.) complement + +ands :: Boolean a => [a] -> a -- or use mconcat with And monoid +ands xs | null xs = true + | otherwise = foldr1 (<&&>) xs + +ors :: Boolean a => [a] -> a +ors xs | null xs = false + | otherwise = foldr1 (<||>) xs + +implies :: Boolean a => a -> a -> a +implies a b = complement a <||> b + +equivalent :: Boolean a => a -> a -> a +equivalent a b = (a <&&> b) <||> (complement a <&&> complement b) ----------------------------------------------------------- -- Buggy and Minor properties
src/Ideas/Common/Context.hs view
@@ -29,15 +29,14 @@ , currentTerm, changeTerm, replaceInContext, currentInContext, changeInContext ) where -import Control.Monad import Data.Maybe import Ideas.Common.Environment import Ideas.Common.Id import Ideas.Common.Rewriting import Ideas.Common.Traversal.Navigator import Ideas.Common.Traversal.Utils -import Ideas.Common.Utils.Uniplate import Ideas.Common.View hiding (left, right) +import Ideas.Utils.Uniplate ---------------------------------------------------------- -- Abstract data type @@ -53,13 +52,13 @@ currentNavigator . getNavigator . top fromContextWith :: Monad m => (a -> b) -> Context a -> m b -fromContextWith f = liftM f . fromContext +fromContextWith f = fmap f . fromContext fromContextWith2 :: Monad m => (a -> b -> c) -> Context a -> Context b -> m c -fromContextWith2 f a b = liftM2 f (fromContext a) (fromContext b) +fromContextWith2 f a b = f <$> fromContext a <*> fromContext b instance Eq a => Eq (Context a) where - x == y = fromMaybe False $ liftM2 (==) (fromContext x) (fromContext y) + x == y = fromMaybe False $ (==) <$> fromContext x <*> fromContext y instance Show a => Show (Context a) where show c@(C env a) = @@ -103,8 +102,8 @@ liftCN :: Monad m => (forall b . Navigator b => b -> m b) -> Context a -> m (Context a) -liftCN f (C env (TermNav a)) = liftM (C env . TermNav) (f a) -liftCN f (C env (Simple a)) = liftM (C env . Simple) (f a) +liftCN f (C env (TermNav a)) = (C env . TermNav) <$> f a +liftCN f (C env (Simple a)) = (C env . Simple) <$> f a liftCN _ (C _ (NoNav _)) = fail "noNavigator" navLocation :: ContextNavigator a -> Location @@ -127,7 +126,7 @@ currentT _ = Nothing changeT :: (Term -> Maybe Term) -> ContextNavigator a -> Maybe (ContextNavigator a) -changeT f (TermNav a) = fmap TermNav (changeM f a) +changeT f (TermNav a) = TermNav <$> changeM f a changeT _ _ = Nothing castT :: IsTerm b => ContextNavigator a -> Maybe (ContextNavigator b) @@ -160,7 +159,7 @@ useC = liftViewIn (makeView f g) where f old@(C env a) = castT a >>= \b -> return (C env b, old) - g (C env a, old) = fromMaybe old (liftM (C env) (castT a)) + g (C env a, old) = fromMaybe old (C env <$> castT a) currentTerm :: Context a -> Maybe Term currentTerm = currentT . getNavigator
− src/Ideas/Common/CyclicTree.hs
@@ -1,218 +0,0 @@------------------------------------------------------------------------------ --- Copyright 2016, Ideas project team. This file is distributed under the --- terms of the Apache License 2.0. For more information, see the files --- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution. ------------------------------------------------------------------------------ --- | --- Maintainer : bastiaan.heeren@ou.nl --- Stability : provisional --- Portability : portable (depends on ghc) --- ------------------------------------------------------------------------------ - -module Ideas.Common.CyclicTree - ( -- * Data type - CyclicTree - -- * Constructor functions - , node, node0, node1, node2, leaf, label - -- * Querying - , isNode, isLeaf, isLabel - -- * Replace functions - , replaceNode, replaceLeaf, replaceLabel, shrinkTree - -- * Fold and algebra - , fold, foldUnwind - , CyclicTreeAlg, fNode, fLeaf, fLabel, fRec, fVar - , emptyAlg, monoidAlg - ) where - -import Control.Applicative -import Control.Monad -import Data.List (intercalate) -import Ideas.Common.Classes -import Ideas.Common.Id -import Test.QuickCheck hiding (label) - --------------------------------------------------------------- --- Data type - -data CyclicTree a b - = Node a [CyclicTree a b] - | Leaf b - | Label Id (CyclicTree a b) - | Rec Int (CyclicTree a b) - | Var Int - -instance (Show a, Show b) => Show (CyclicTree a b) where - show = fold Alg - { fNode = \a xs -> show a ++ par xs - , fLeaf = show - , fLabel = \l s -> show l ++ ":" ++ s - , fRec = \n s -> '#' : show n ++ "=" ++ s - , fVar = \n -> '#' : show n - } - -instance BiFunctor CyclicTree where - biMap f g = fold idAlg {fNode = Node . f, fLeaf = Leaf . g} - -instance Functor (CyclicTree d) where - fmap = mapSecond - -instance Applicative (CyclicTree d) where - pure = leaf - p <*> q = fold idAlg {fLeaf = (`fmap` q)} p - -instance Monad (CyclicTree d) where - return = leaf - (>>=) = flip replaceLeaf - -instance Foldable (CyclicTree d) where - foldMap f = fold monoidAlg {fLeaf = f} - -instance Traversable (CyclicTree d) where - traverse f = fold emptyAlg - { fNode = \a -> liftA (node a) . sequenceA - , fLeaf = liftA leaf . f - , fLabel = liftA . label - , fRec = liftA . Rec - , fVar = pure . Var - } - -instance Fix (CyclicTree a b) where - fix f = Rec n (f (Var n)) - where - vs = vars (f (Var (-1))) - n = maximum (-1 : vs) + 1 - -instance (Arbitrary a, Arbitrary b) => Arbitrary (CyclicTree a b) where - arbitrary = sized arbTree - shrink = shrinkTree - -arbTree :: (Arbitrary a, Arbitrary b) => Int -> Gen (CyclicTree a b) -arbTree = rec 0 - where - rec vi 0 = frequency $ - (3, liftM leaf arbitrary) - : [ (1, elements (map Var [1..vi])) | vi > 0 ] - rec vi n = frequency - [ (3, liftM2 node arbitrary ms) - , (2, rec vi 0) - , (1, liftM2 label genId m) - , (1, liftM (Rec (vi+1)) (rec (vi+1) (n `div` 2))) - ] - where - m = rec vi (n `div` 2) - genId = elements [ newId [c] | c <- ['A' .. 'Z']] - ms = choose (0, 3) >>= \i -> replicateM i m - -shrinkTree :: CyclicTree a b -> [CyclicTree a b] -shrinkTree tree = - case tree of - Node a ts -> ts ++ map (node a) (shrinkTrees ts) - Label l t -> t : map (Label l) (shrinkTree t) - Rec n t -> map (Rec n) (shrinkTree t) - _ -> [] - --- shrink exactly one tree -shrinkTrees :: [CyclicTree a b] -> [[CyclicTree a b]] -shrinkTrees [] = [] -shrinkTrees (t:ts) = map (:ts) (shrinkTree t) ++ map (t:) (shrinkTrees ts) - --- local helpers -par :: [String] -> String -par xs | null xs = "" - | otherwise = "(" ++ intercalate ", " xs ++ ")" - -vars :: CyclicTree a b -> [Int] -vars = fold monoidAlg {fVar = return} - --------------------------------------------------------------- --- Constructor functions - -node :: a -> [CyclicTree a b] -> CyclicTree a b -node = Node - -node0 :: a -> CyclicTree a b -node0 a = node a [] - -node1 :: a -> CyclicTree a b -> CyclicTree a b -node1 a x = node a [x] - -node2 :: a -> CyclicTree a b -> CyclicTree a b -> CyclicTree a b -node2 a x y = node a [x, y] - -leaf :: b -> CyclicTree a b -leaf = Leaf - -label :: IsId n => n -> CyclicTree a b -> CyclicTree a b -label = Label . newId - --------------------------------------------------------------- --- Querying - -isNode :: CyclicTree a b -> Maybe (a, [CyclicTree a b]) -isNode (Node a xs) = Just (a, xs) -isNode _ = Nothing - -isLeaf :: CyclicTree a b -> Maybe b -isLeaf (Leaf b) = Just b -isLeaf _ = Nothing - -isLabel :: CyclicTree a b -> Maybe (Id, CyclicTree a b) -isLabel (Label l t) = Just (l, t) -isLabel _ = Nothing - --------------------------------------------------------------- --- Replace functions - -replaceNode :: (a -> [CyclicTree a b] -> CyclicTree a b) -> CyclicTree a b -> CyclicTree a b -replaceNode f = fold idAlg {fNode = f} - -replaceLabel :: (Id -> CyclicTree a b -> CyclicTree a b) -> CyclicTree a b -> CyclicTree a b -replaceLabel f = fold idAlg {fLabel = f} - -replaceLeaf :: (b -> CyclicTree a c) -> CyclicTree a b -> CyclicTree a c -replaceLeaf f = fold idAlg {fLeaf = f} - --------------------------------------------------------------- --- Fold and algebra - -fold :: CyclicTreeAlg a b t -> CyclicTree a b -> t -fold alg = rec - where - rec (Node a ts) = fNode alg a (map rec ts) - rec (Leaf b) = fLeaf alg b - rec (Label l t) = fLabel alg l (rec t) - rec (Rec n t) = fRec alg n (rec t) - rec (Var n) = fVar alg n - -foldUnwind :: CyclicTreeAlg a b t -> CyclicTree a b -> t -foldUnwind alg = start . fold Alg - { fNode = \a fs sub -> fNode alg a (map ($ sub) fs) - , fLeaf = \b _ -> fLeaf alg b - , fLabel = \l f sub -> fLabel alg l (f sub) - , fRec = \n f sub -> let this = f (extend n this sub) - in this - , fVar = \n sub -> sub n - } - where - start f = f (error "foldUnwind: unbound var") - extend n a sub i - | i == n = a - | otherwise = sub i - -data CyclicTreeAlg a b t = Alg - { fNode :: a -> [t] -> t - , fLeaf :: b -> t - , fLabel :: Id -> t -> t - , fRec :: Int -> t -> t - , fVar :: Int -> t - } - -idAlg :: CyclicTreeAlg a b (CyclicTree a b) -idAlg = Alg Node Leaf Label Rec Var - -emptyAlg :: CyclicTreeAlg a b t -emptyAlg = let f = error "emptyAlg: uninitialized" in Alg f f f f f - -monoidAlg :: Monoid m => CyclicTreeAlg a b m -monoidAlg = Alg (const mconcat) mempty (const id) (const id) mempty
src/Ideas/Common/Environment.hs view
@@ -15,7 +15,7 @@ module Ideas.Common.Environment ( -- * Reference - Ref, Reference(..) + Ref, Reference(..), mapRef -- * Binding , Binding, makeBinding , fromBinding, showValue, getTermValue @@ -28,11 +28,11 @@ import Control.Monad import Data.Function import Data.List -import Data.Typeable import Ideas.Common.Id import Ideas.Common.Rewriting.Term -import Ideas.Common.Utils import Ideas.Common.View +import Ideas.Utils.Prelude +import Ideas.Utils.Typeable import qualified Data.Map as M ----------------------------------------------------------- @@ -40,10 +40,11 @@ -- | A data type for references (without a value) data Ref a = Ref - { identifier :: Id -- ^ Identifier - , printer :: a -> String -- ^ A pretty-printer - , parser :: String -> Maybe a -- ^ A parser - , refView :: View Term a -- ^ Conversion to/from term + { identifier :: Id -- Identifier + , printer :: a -> String -- Pretty-printer + , parser :: String -> Maybe a -- Parser + , refView :: View Term a -- Conversion to/from term + , refType :: IsTypeable a } instance Show (Ref a) where @@ -56,20 +57,23 @@ getId = identifier changeId f d = d {identifier = f (identifier d)} +instance HasTypeable Ref where + getTypeable = Just . refType + -- | A type class for types as references class (IsTerm a, Typeable a, Show a, Read a) => Reference a where makeRef :: IsId n => n -> Ref a makeRefList :: IsId n => n -> Ref [a] -- default implementation - makeRef n = Ref (newId n) show readM termView - makeRefList n = Ref (newId n) show readM termView + makeRef n = Ref (newId n) show readM termView typeable + makeRefList n = Ref (newId n) show readM termView typeable instance Reference Int instance Reference Term instance Reference Char where - makeRefList n = Ref (newId n) id Just variableView + makeRefList n = Ref (newId n) id Just variableView typeable instance Reference ShowString @@ -78,33 +82,41 @@ instance (Reference a, Reference b) => Reference (a, b) +mapRef :: Typeable b => Isomorphism a b -> Ref a -> Ref b +mapRef iso r = r + { printer = printer r . to iso + , parser = fmap (from iso) . parser r + , refView = refView r >>> toView iso + , refType = typeable + } + ----------------------------------------------------------- -- Binding -data Binding = forall a . Typeable a => Binding (Ref a) a +data Binding = forall a . Binding (Ref a) a instance Show Binding where show a = showId a ++ "=" ++ showValue a instance Eq Binding where - (==) = let f (Binding ref a) = (getId ref, build (refView ref) a) + (==) = let f (Binding r a) = (getId r, build (refView r) a) in (==) `on` f instance HasId Binding where - getId (Binding ref _ ) = getId ref - changeId f (Binding ref a) = Binding (changeId f ref) a + getId (Binding r _ ) = getId r + changeId f (Binding r a) = Binding (changeId f r) a -makeBinding :: Typeable a => Ref a -> a -> Binding +makeBinding :: Ref a -> a -> Binding makeBinding = Binding fromBinding :: Typeable a => Binding -> Maybe (Ref a, a) -fromBinding (Binding ref a) = liftM2 (,) (gcast ref) (cast a) +fromBinding (Binding r a) = liftM2 (,) (gcastFrom r r) (castFrom r a) showValue :: Binding -> String -showValue (Binding ref a) = printer ref a +showValue (Binding r a) = printer r a getTermValue :: Binding -> Term -getTermValue (Binding ref a) = build (refView ref) a +getTermValue (Binding r a) = build (refView r) a ----------------------------------------------------------- -- Heterogeneous environment @@ -125,22 +137,22 @@ makeEnvironment :: [Binding] -> Environment makeEnvironment xs = Env $ M.fromList [ (getId a, a) | a <- xs ] -singleBinding :: Typeable a => Ref a -> a -> Environment -singleBinding ref = makeEnvironment . return . Binding ref +singleBinding :: Ref a -> a -> Environment +singleBinding r = makeEnvironment . return . Binding r class HasEnvironment env where environment :: env -> Environment setEnvironment :: Environment -> env -> env deleteRef :: Ref a -> env -> env - insertRef :: Typeable a => Ref a -> a -> env -> env - changeRef :: Typeable a => Ref a -> (a -> a) -> env -> env + insertRef :: Ref a -> a -> env -> env + changeRef :: Ref a -> (a -> a) -> env -> env -- default definitions deleteRef a = changeEnv (Env . M.delete (getId a) . envMap) - insertRef ref = + insertRef r = let f b = Env . M.insert (getId b) b . envMap - in changeEnv . f . Binding ref - changeRef ref f env = - maybe id (insertRef ref . f) (ref ? env) env + in changeEnv . f . Binding r + changeRef r f env = + maybe id (insertRef r . f) (r ? env) env -- local helper changeEnv :: HasEnvironment env => (Environment -> Environment) -> env -> env @@ -168,11 +180,11 @@ noBindings :: HasEnvironment env => env -> Bool noBindings = M.null . envMap . environment -(?) :: (HasEnvironment env, Typeable a) => Ref a -> env -> Maybe a +(?) :: HasEnvironment env => Ref a -> env -> Maybe a ref ? env = do let m = envMap (environment env) - Binding _ a <- M.lookup (getId ref) m - msum [ cast a -- typed value - , cast a >>= parser ref -- value as string - , cast a >>= match (refView ref) -- value as term + Binding r a <- M.lookup (getId ref) m + msum [ castBetween r ref a -- typed value + , castFrom r a >>= parser ref -- value as string + , castFrom r a >>= match (refView ref) -- value as term ]
src/Ideas/Common/Exercise.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE Rank2Types, DeriveDataTypeable #-} +{-# LANGUAGE Rank2Types, ExistentialQuantification #-} ----------------------------------------------------------------------------- -- Copyright 2016, Ideas project team. This file is distributed under the -- terms of the Apache License 2.0. For more information, see the files @@ -32,7 +32,7 @@ -- * Type casting , useTypeable, castFrom, castTo -- * Exercise properties - , setProperty, getProperty + , setProperty, getProperty, setPropertyF, getPropertyF -- * Random generators , simpleGenerator, useGenerator, randomTerm, randomTerms -- * Derivations @@ -41,8 +41,6 @@ ) where import Data.Char -import Data.Data -import Data.Dynamic import Data.List import Data.Maybe import Data.Ord @@ -55,8 +53,9 @@ import Ideas.Common.Rewriting import Ideas.Common.Rule import Ideas.Common.Strategy hiding (not, fail, repeat, replicate) -import Ideas.Common.Utils (ShowString(..)) import Ideas.Common.View +import Ideas.Utils.Prelude (ShowString(..)) +import Ideas.Utils.Typeable import System.Random import Test.QuickCheck hiding (label) import Test.QuickCheck.Gen @@ -129,7 +128,7 @@ , hasTypeable :: Maybe (IsTypeable a) -- | Extra exercise-specific properties, not used by the default -- feedback services. - , properties :: M.Map String Dynamic -- extra, domain-specific properties + , properties :: M.Map Id (Dynamic a) -- extra, domain-specific properties } instance Eq (Exercise a) where @@ -202,7 +201,7 @@ -- | Returns a sorted list of rules, without duplicates. ruleset :: Exercise a -> [Rule (Context a)] -ruleset ex = nub (sortBy compareId list) +ruleset ex = nub (sortBy (ruleOrdering ex) list) where list = extraRules ex ++ rulesInStrategy (strategy ex) @@ -252,7 +251,7 @@ type Examples a = [(Difficulty, a)] data Difficulty = VeryEasy | Easy | Medium | Difficult | VeryDifficult - deriving (Eq, Ord, Enum, Data, Typeable) + deriving (Eq, Ord, Enum) instance Show Difficulty where show = (xs !!) . fromEnum @@ -310,38 +309,55 @@ ----------------------------------------------------------------------------- -- Type casting -data IsTypeable a = IT (forall b . Typeable b => a -> Maybe b) - (forall b . Typeable b => b -> Maybe a) +instance HasTypeable Exercise where + getTypeable = hasTypeable -- | Encapsulates a type representation (use for 'hasTypeable' field). useTypeable :: Typeable a => Maybe (IsTypeable a) -useTypeable = Just (IT cast cast) - --- | Cast from polymorphic type (to exercise-specific type). --- This only works if 'hasTypeable' contains the right type representation. -castFrom :: Typeable b => Exercise a -> a -> Maybe b -castFrom ex a = do - IT f _ <- hasTypeable ex - f a - --- | Cast to polymorphic type (from exercise-specific type). --- This only works if 'hasTypeable' contains the right type representation. -castTo :: Typeable b => Exercise a -> b -> Maybe a -castTo ex a = do - IT _ g <- hasTypeable ex - g a +useTypeable = Just typeable ----------------------------------------------------------------------------- -- Exercise-specific properties -- | Set an exercise-specific property (with a dynamic type) -setProperty :: Typeable val => String -> val -> Exercise a -> Exercise a -setProperty key a ex = - ex { properties = M.insert key (toDyn a) (properties ex) } +setProperty :: (IsId n, Typeable val) => n -> val -> Exercise a -> Exercise a +setProperty key a = insertProperty key (Dyn (cast a)) +-- | Set an exercise-specific property (with a dynamic type) that is +-- parameterized over the exercise term. +setPropertyF :: (IsId n, Typeable f) => n -> f a -> Exercise a -> Exercise a +setPropertyF key a = insertProperty key (DynF (castF a)) + +insertProperty :: IsId n => n -> Dynamic a -> Exercise a -> Exercise a +insertProperty key d ex = + ex { properties = M.insert (newId key) d (properties ex) } + -- | Get an exercise-specific property (of a dynamic type) -getProperty :: Typeable val => String -> Exercise a -> Maybe val -getProperty key ex = M.lookup key (properties ex) >>= fromDynamic +getProperty :: (IsId n, Typeable val) => n -> Exercise a -> Maybe val +getProperty key ex = lookupProperty key ex >>= \d -> + case d of + Dyn m -> m + _ -> Nothing + +-- | Get an exercise-specific property (of a dynamic type) that is +-- parameterized over the exercise term. +getPropertyF :: (IsId n, Typeable f) => n -> Exercise a -> Maybe (f a) +getPropertyF key ex = lookupProperty key ex >>= \d -> + case d of + DynF m -> m + _ -> Nothing + +lookupProperty :: IsId n => n -> Exercise a -> Maybe (Dynamic a) +lookupProperty key = M.lookup (newId key) . properties + +-- | Values with a dynamic type that is parameterized over the exercise term. +data Dynamic a = Dyn (forall b . Typeable b => Maybe b) + | DynF (forall f . Typeable f => Maybe (f a)) + +castF :: (Typeable f, Typeable g) => f a -> Maybe (g a) +castF = fmap fromIdentity . gcast1 . Identity + +newtype Identity a = Identity { fromIdentity :: a} --------------------------------------------------------------- -- Random generators
src/Ideas/Common/ExerciseTests.hs view
@@ -23,8 +23,8 @@ import Ideas.Common.Exercise import Ideas.Common.Id import Ideas.Common.Rule -import Ideas.Common.Utils.TestSuite import Ideas.Common.View +import Ideas.Utils.TestSuite import Test.QuickCheck import Test.QuickCheck.Random @@ -54,7 +54,7 @@ checkParserPrettyEx ex . inContext ex . fromS , suite "Soundness non-buggy rules" $ let eq a b = equivalence ex (fromS a) (fromS b) - myGen = showAs (prettyPrinterContext ex) (liftM (inContext ex) gen) + myGen = showAs (prettyPrinterContext ex) (inContext ex <$> gen) myView = makeView (Just . fromS) (S (prettyPrinterContext ex)) args = stdArgs {maxSize = 10, maxSuccess = 10} in [ usePropertyWith (showId r) args $ @@ -81,7 +81,7 @@ show a = showS a (fromS a) showAs :: (a -> String) -> Gen a -> Gen (ShowAs a) -showAs f = liftM (S f) +showAs f = fmap (S f) -- check combination of parser and pretty-printer checkParserPretty :: (a -> a -> Bool) -> (String -> Either String a) -> (a -> String) -> a -> Bool
src/Ideas/Common/Id.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE DeriveDataTypeable #-} ----------------------------------------------------------------------------- -- Copyright 2016, Ideas project team. This file is distributed under the -- terms of the Apache License 2.0. For more information, see the files @@ -45,13 +44,12 @@ import Control.Monad import Data.Char -import Data.Data import Data.List import Data.Monoid import Data.Ord import Ideas.Common.Classes -import Ideas.Common.Utils (splitsWithElem) -import Ideas.Common.Utils.StringRef +import Ideas.Utils.Prelude (splitsWithElem) +import Ideas.Utils.StringRef import Test.QuickCheck --------------------------------------------------------------------- @@ -64,7 +62,6 @@ , idDescription :: String , idRef :: !StringRef } - deriving (Data, Typeable) instance Show Id where show = intercalate "." . idList
src/Ideas/Common/Library.hs view
@@ -15,6 +15,7 @@ module Ideas.Common.Library ( module Export , failS, notS, repeatS, replicateS, sequenceS, untilS + , Some(..) ) where import Ideas.Common.Classes as Export @@ -28,8 +29,8 @@ import Ideas.Common.Rule as Export import Ideas.Common.Strategy as Export hiding (fail, not, repeat, replicate, sequence, until) import Ideas.Common.Traversal.Navigator as Export (Location, location, toLocation, fromLocation, arity, top) -import Ideas.Common.Utils as Export (readM) import Ideas.Common.View as Export +import Ideas.Utils.Prelude as Export (readM, Some(..)) import qualified Ideas.Common.Strategy as S
src/Ideas/Common/Predicate.hs view
@@ -22,7 +22,7 @@ , ands, ors, implies, equivalent ) where -import Ideas.Common.Algebra.Boolean +import Ideas.Common.Classes import Ideas.Common.Id import Ideas.Common.View
src/Ideas/Common/Rewriting/Confluence.hs view
@@ -24,7 +24,7 @@ import Ideas.Common.Rewriting.Unification import Ideas.Common.Traversal.Navigator import Ideas.Common.Traversal.Utils -import Ideas.Common.Utils.Uniplate hiding (rewriteM) +import Ideas.Utils.Uniplate hiding (rewriteM) normalForm :: [RewriteRule a] -> Term -> Term normalForm rs = run []
src/Ideas/Common/Rewriting/RewriteRule.hs view
@@ -32,8 +32,8 @@ import Ideas.Common.Rewriting.Substitution import Ideas.Common.Rewriting.Term import Ideas.Common.Rewriting.Unification -import Ideas.Common.Utils.Uniplate (descend) import Ideas.Common.View hiding (match) +import Ideas.Utils.Uniplate (descend) import qualified Data.IntSet as IS import qualified Data.Map as M
src/Ideas/Common/Rewriting/Substitution.hs view
@@ -22,8 +22,8 @@ import Data.List import Data.Maybe import Ideas.Common.Rewriting.Term -import Ideas.Common.Utils.TestSuite -import Ideas.Common.Utils.Uniplate +import Ideas.Utils.TestSuite +import Ideas.Utils.Uniplate import Test.QuickCheck import qualified Data.IntMap as IM import qualified Data.IntSet as IS @@ -91,7 +91,7 @@ infix 6 @+@ (@+@) :: Substitution -> Substitution -> Maybe Substitution -s1 @+@ s2 = liftM S $ foldM op (unS s1) $ IM.toList $ unS s2 +s1 @+@ s2 = fmap S $ foldM op (unS s1) $ IM.toList $ unS s2 where op m (i, a) = case IM.lookup i m of
src/Ideas/Common/Rewriting/Term.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE DeriveDataTypeable #-} {-# OPTIONS -fno-warn-orphans #-} ----------------------------------------------------------------------------- -- Copyright 2016, Ideas project team. This file is distributed under the @@ -18,6 +17,7 @@ ( -- * Symbols Symbol, newSymbol , isAssociative, makeAssociative + , nothingSymbol, trueSymbol, falseSymbol -- * Terms , Term(..), IsTerm(..), termView , fromTermM, fromTermWith @@ -34,15 +34,15 @@ ) where import Control.Monad -import Data.Data import Data.Function import Data.Maybe import Ideas.Common.Id -import Ideas.Common.Utils (ShowString(..)) -import Ideas.Common.Utils.QuickCheck -import Ideas.Common.Utils.Uniplate import Ideas.Common.View +import Ideas.Utils.Prelude (ShowString(..)) +import Ideas.Utils.QuickCheck +import Ideas.Utils.Uniplate import qualified Data.IntSet as IS +import qualified Data.Map as M import qualified Data.Set as S ----------------------------------------------------------- @@ -84,7 +84,7 @@ | TNum Integer | TFloat Double | TMeta Int - deriving (Show, Read, Eq, Ord, Typeable) + deriving (Show, Read, Eq, Ord) instance Uniplate Term where uniplate (TCon x xs) = plate (function x) ||* xs @@ -95,8 +95,14 @@ -- * Type class for conversion to/from terms class IsTerm a where - toTerm :: a -> Term - fromTerm :: MonadPlus m => Term -> m a + toTerm :: a -> Term + toTermList :: [a] -> Term + fromTerm :: MonadPlus m => Term -> m a + fromTermList :: MonadPlus m => Term -> m [a] + -- default implementation + toTermList = TList . map toTerm + fromTermList (TList xs) = mapM fromTerm xs + fromTermList _ = fail "fromTermList: not a list" termView :: IsTerm a => View Term a termView = makeView fromTerm toTerm @@ -112,18 +118,18 @@ instance (IsTerm a, IsTerm b) => IsTerm (a, b) where toTerm (a, b) = TList [toTerm a, toTerm b] - fromTerm (TList [a, b]) = liftM2 (,) (fromTerm a) (fromTerm b) + fromTerm (TList [a, b]) = (,) <$> fromTerm a <*> fromTerm b fromTerm _ = fail "fromTerm" instance (IsTerm a, IsTerm b) => IsTerm (Either a b) where toTerm = either toTerm toTerm fromTerm expr = - liftM Left (fromTerm expr) `mplus` - liftM Right (fromTerm expr) + fmap Left (fromTerm expr) `mplus` + fmap Right (fromTerm expr) instance IsTerm Int where toTerm = TNum . fromIntegral - fromTerm = liftM fromInteger . fromTerm + fromTerm = fmap fromInteger . fromTerm instance IsTerm Integer where toTerm = TNum @@ -137,13 +143,41 @@ instance IsTerm Char where toTerm c = TVar [c] - fromTerm (TVar [c]) = return c - fromTerm _ = fail "fromTerm" + toTermList = TVar + fromTerm (TVar [c]) = return c + fromTerm _ = fail "fromTerm: not a TVar" + fromTermList (TVar s) = return s + fromTermList _ = fail "fromTermList: not a TVar" +instance IsTerm Bool where + toTerm True = symbol trueSymbol + toTerm False = symbol falseSymbol + fromTerm (TCon s []) + | s == trueSymbol = return True + | s == falseSymbol = return False + fromTerm _ = fail "fromTerm: not a Bool" + instance IsTerm a => IsTerm [a] where - toTerm = TList . map toTerm - fromTerm (TList xs) = mapM fromTerm xs - fromTerm _ = fail "fromTerm" + toTerm = toTermList + fromTerm = fromTermList + +instance (IsTerm a, Ord a) => IsTerm (S.Set a) where + toTerm = toTerm . S.toList + fromTerm = fmap S.fromList . fromTerm + +instance (IsTerm a, IsTerm b, Ord a) => IsTerm (M.Map a b) where + toTerm = toTerm . M.toList + fromTerm = fmap M.fromList . fromTerm + +trueSymbol, falseSymbol, nothingSymbol :: Symbol +trueSymbol = newSymbol "true" +falseSymbol = newSymbol "false" +nothingSymbol = newSymbol "Nothing" + +instance IsTerm a => IsTerm (Maybe a) where + toTerm = maybe (symbol nothingSymbol) toTerm + fromTerm (TCon s []) | s == nothingSymbol = return Nothing + fromTerm t = fmap Just (fromTerm t) fromTermM :: (Monad m, IsTerm a) => Term -> m a fromTermM = maybe (fail "fromTermM") return . fromTerm
src/Ideas/Common/Rewriting/Unification.hs view
@@ -21,7 +21,7 @@ import Ideas.Common.Rewriting.AC (pairingsMatchA) import Ideas.Common.Rewriting.Substitution import Ideas.Common.Rewriting.Term -import Ideas.Common.Utils.TestSuite +import Ideas.Utils.TestSuite import qualified Data.Map as M ----------------------------------------------------------- @@ -141,7 +141,7 @@ safeZipWith f = rec where rec [] [] = Just [] - rec (a:as) (b:bs) = liftM (f a b:) (rec as bs) + rec (a:as) (b:bs) = fmap (f a b:) (rec as bs) rec _ _ = Nothing products :: [[Substitution]] -> [Substitution]
src/Ideas/Common/Rule.hs view
@@ -13,7 +13,6 @@ module Ideas.Common.Rule (module Export) where import Ideas.Common.Rule.Abstract as Export -import Ideas.Common.Rule.EnvironmentMonad as Export import Ideas.Common.Rule.Parameter as Export import Ideas.Common.Rule.Recognizer as Export import Ideas.Common.Rule.Transformation as Export
src/Ideas/Common/Rule/Abstract.hs view
@@ -25,10 +25,10 @@ , idRule, checkRule, emptyRule -- * Rule properties , ruleSiblings, siblingOf - , isRewriteRule, isRecognizer, doAfter + , isRewriteRule, doAfter -- * Recognizer , addRecognizer, addRecognizerBool - , addTransRecognizer, addRecognizerEnvMonad + , addTransRecognizer ) where import Control.Arrow @@ -37,7 +37,6 @@ import Ideas.Common.Environment import Ideas.Common.Id import Ideas.Common.Rewriting -import Ideas.Common.Rule.EnvironmentMonad import Ideas.Common.Rule.Recognizer import Ideas.Common.Rule.Transformation import Ideas.Common.View @@ -155,9 +154,6 @@ isRewriteRule :: Rule a -> Bool isRewriteRule = not . null . getRewriteRules . transformation -isRecognizer :: Rule a -> Bool -isRecognizer = isZeroTrans . transformation - siblingOf :: HasId b => b -> Rule a -> Rule a siblingOf sib r = r { ruleSiblings = getId sib : ruleSiblings r } @@ -173,9 +169,6 @@ addRecognizerBool :: (a -> a -> Bool) -> Rule a -> Rule a addRecognizerBool eq = addRecognizer (makeRecognizer eq) - -addRecognizerEnvMonad :: (a -> a -> EnvMonad ()) -> Rule a -> Rule a -addRecognizerEnvMonad = addRecognizer . makeRecognizerEnvMonad addTransRecognizer :: (a -> a -> Bool) -> Rule a -> Rule a addTransRecognizer eq r = flip addRecognizer r $
− src/Ideas/Common/Rule/EnvironmentMonad.hs
@@ -1,132 +0,0 @@-{-# LANGUAGE GADTs #-} ------------------------------------------------------------------------------ --- Copyright 2016, Ideas project team. This file is distributed under the --- terms of the Apache License 2.0. For more information, see the files --- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution. ------------------------------------------------------------------------------ --- | --- Maintainer : bastiaan.heeren@ou.nl --- Stability : provisional --- Portability : portable (depends on ghc) --- --- State monad for environments --- ------------------------------------------------------------------------------ - -module Ideas.Common.Rule.EnvironmentMonad - ( -- * Environment Monad - EnvMonad((:=), (:~), (:?)) - , getRef, updateRefs - -- * Running the monad - , runEnvMonad, execEnvMonad, evalEnvMonad - -- * Extracting used references - , envMonadRefs, envMonadFunctionRefs - ) where - -import Control.Applicative (Alternative(..)) -import Control.Monad -import Data.Maybe -import Data.Typeable -import Ideas.Common.Environment -import Ideas.Common.Utils -import System.IO.Unsafe -import qualified Control.Exception as C - ------------------------------------------------------------ --- Environment Monad - -infix 2 :=, :~, :? - -data EnvMonad a where - -- Monad operations - Return :: a -> EnvMonad a - Bind :: EnvMonad a -> (a -> EnvMonad b) -> EnvMonad b - Then :: EnvMonad a -> EnvMonad b -> EnvMonad b - Fail :: String -> EnvMonad b - -- MonadPlus operations - Zero :: EnvMonad a - Plus :: EnvMonad a -> EnvMonad a -> EnvMonad a - -- References (special) - (:=) :: Typeable a => Ref a -> a -> EnvMonad () - (:~) :: Typeable a => Ref a -> (a -> a) -> EnvMonad () - (:?) :: Typeable a => Ref a -> a -> EnvMonad a - GetRef :: Typeable a => Ref a -> EnvMonad a - -instance Functor EnvMonad where - fmap = liftM - -instance Applicative EnvMonad where - pure = return - (<*>) = ap - -instance Alternative EnvMonad where - empty = Zero - (<|>) = Plus - -instance Monad EnvMonad where - return = Return - (>>=) = Bind - fail = Fail - -instance MonadPlus EnvMonad where - mzero = Zero - mplus = Plus - -getRef :: Typeable a => Ref a -> EnvMonad a -getRef = GetRef - -updateRefs :: MonadPlus m => [EnvMonad a] -> Environment -> m Environment -updateRefs xs = msum . map return . execEnvMonad (sequence_ xs) - ------------------------------------------------------------ --- Environment Monad - -runEnvMonad :: EnvMonad a -> Environment -> [(a, Environment)] -runEnvMonad envMonad env = - case envMonad of - Return a -> [(a, env)] - Bind m f -> concat [ runEnvMonad (f a) e | (a, e) <- runEnvMonad m env ] - Then m n -> concat [ runEnvMonad n e | (_, e) <- runEnvMonad m env ] - Fail _ -> [] - Zero -> [] - Plus m n -> runEnvMonad m env ++ runEnvMonad n env - ref := a -> [((), insertRef ref a env)] - ref :~ f -> [((), changeRef ref f env)] - ref :? a -> [(fromMaybe a (ref ? env), env)] - GetRef ref -> case ref ? env of - Just a -> [(a, env)] - Nothing -> [] - -execEnvMonad :: EnvMonad a -> Environment -> [Environment] -execEnvMonad m = liftM snd . runEnvMonad m - -evalEnvMonad :: EnvMonad a -> Environment -> [a] -evalEnvMonad m = liftM fst . runEnvMonad m - ------------------------------------------------------------ --- Extracting used references - -envMonadRefs :: EnvMonad a -> [Some Ref] -envMonadRefs = unsafePerformIO . safeIO . envMonadRefsIO - -envMonadFunctionRefs :: (a -> EnvMonad b) -> [Some Ref] -envMonadFunctionRefs = unsafePerformIO . safeIO . envMonadFunctionRefsIO - -envMonadRefsIO :: EnvMonad a -> IO [Some Ref] -envMonadRefsIO monad = - case monad of - Bind m f -> envMonadRefsIO m ++++ envMonadFunctionRefsIO f - Then a b -> envMonadRefsIO a ++++ envMonadRefsIO b - Plus a b -> envMonadRefsIO a ++++ envMonadRefsIO b - r := _ -> return [Some r] - r :~ _ -> return [Some r] - r :? _ -> return [Some r] - _ -> return [] - where - a ++++ b = liftM2 (++) (safeIO a) (safeIO b) - -envMonadFunctionRefsIO :: (a -> EnvMonad b) -> IO [Some Ref] -envMonadFunctionRefsIO = safeIO . envMonadRefsIO . ($ error "catch me") - -safeIO :: IO [a] -> IO [a] -safeIO m = m `C.catch` \(C.SomeException _) -> return []
src/Ideas/Common/Rule/Parameter.hs view
@@ -17,44 +17,119 @@ ----------------------------------------------------------------------------- module Ideas.Common.Rule.Parameter - ( ParamTrans - , supplyParameters, supplyContextParameters + ( -- * Reading inputs + input, inputWith + , transInput1, transInput2, transInput3, transInputWith + , readRef2, readRef3 + -- * Writing outputs + , output, outputWith + , outputOnly, outputOnly2, outputOnly3, outputOnlyWith + , writeRef2, writeRef3, writeRef2_, writeRef3_ + -- * Named parameters + , ParamTrans , parameter1, parameter2, parameter3 + , transRef + , supplyParameters ) where import Control.Arrow +import Data.Maybe import Ideas.Common.Context import Ideas.Common.Environment -import Ideas.Common.Id -import Ideas.Common.Rule.EnvironmentMonad import Ideas.Common.Rule.Transformation import Ideas.Common.View ------------------------------------------------------------ ---- Bindables +---------------------------------------------------------------------------- +-- Reading inputs -type ParamTrans a b = Trans (a, b) b +input :: Ref i -> Trans (i, a) b -> Trans a b +input = inputWith . readRef -supplyParameters :: ParamTrans b a -> (a -> Maybe b) -> Transformation a -supplyParameters f g = transMaybe g &&& identity >>> f +inputWith :: Trans a i -> Trans (i, a) b -> Trans a b +inputWith f g = (f &&& identity) >>> g -supplyContextParameters :: ParamTrans b a -> (a -> EnvMonad b) -> Transformation (Context a) -supplyContextParameters f g = transLiftContextIn $ - transUseEnvironment (transEnvMonad g &&& identity) >>> first f +transInput1 :: Ref i -> (i -> a -> Maybe b) -> Trans a b +transInput1 = transInputWith . readRef -parameter1 :: (IsId n1, Reference a) => n1 -> (a -> Transformation b) -> ParamTrans a b -parameter1 n1 f = first (bindValue n1 >>> arr f) >>> app +transInput2 :: Ref i1 -> Ref i2 -> (i1 -> i2 -> a -> Maybe b) -> Trans a b +transInput2 r1 r2 = transInputWith (readRef2 r1 r2) . uncurry -parameter2 :: (IsId n1, IsId n2, Reference a, Reference b) - => n1 -> n2 -> (a -> b -> Transformation c) -> ParamTrans (a, b) c -parameter2 n1 n2 f = first (bindValue n1 *** bindValue n2 >>> arr (uncurry f)) >>> app +transInput3 :: Ref i1 -> Ref i2 -> Ref i3 -> (i1 -> i2 -> i3 -> a -> Maybe b) -> Trans a b +transInput3 r1 r2 r3 = transInputWith (readRef3 r1 r2 r3) . uncurry3 -parameter3 :: (IsId n1, IsId n2, IsId n3, Reference a, Reference b, Reference c) - => n1 -> n2 -> n3 -> (a -> b -> c -> Transformation d) -> ParamTrans (a, b, c) d -parameter3 n1 n2 n3 f = first ((\(a, b, c) -> (a, (b, c))) ^>> - bindValue n1 *** (bindValue n2 *** bindValue n3) >>^ - (\(a, (b, c)) -> f a b c)) - >>> app +transInputWith :: MakeTrans f => Trans a i -> (i -> a -> f b) -> Trans a b +transInputWith t = inputWith t . makeTrans . uncurry -bindValue :: (IsId n, Reference a) => n -> Trans a a -bindValue = transRef . makeRef+readRef2 :: Ref a -> Ref b -> Trans x (a, b) +readRef2 r1 r2 = readRef r1 &&& readRef r2 + +readRef3 :: Ref a -> Ref b -> Ref c -> Trans x (a, b, c) +readRef3 r1 r2 r3 = readRef r1 &&& readRef2 r2 r3 >>^ to3 + +---------------------------------------------------------------------------- +-- Writing outputs + +output :: Ref o -> Trans a (b, o) -> Trans a b +output = outputWith . writeRef + +outputWith :: Trans o x -> Trans a (b, o) -> Trans a b +outputWith f g = g >>> second f >>^ fst + +outputOnly :: Ref o -> Trans a o -> Trans a a +outputOnly = outputOnlyWith . writeRef + +outputOnly2 :: Ref o1 -> Ref o2 -> Trans a (o1, o2) -> Trans a a +outputOnly2 r1 = outputOnlyWith . writeRef2 r1 + +outputOnly3 :: Ref o1 -> Ref o2 -> Ref o3 -> Trans a (o1, o2, o3) -> Trans a a +outputOnly3 r1 r2 = outputOnlyWith . writeRef3 r1 r2 + +outputOnlyWith :: Trans o x -> Trans a o -> Trans a a +outputOnlyWith f g = ((g >>> f) &&& identity) >>^ snd + +writeRef2 :: Ref a -> Ref b -> Trans (a, b) (a, b) +writeRef2 r1 r2 = writeRef r1 *** writeRef r2 + +writeRef2_ :: Ref a -> Ref b -> Trans (a, b) () +writeRef2_ r1 r2 = writeRef2 r1 r2 >>^ const () + +writeRef3 :: Ref a -> Ref b -> Ref c -> Trans (a, b, c) (a, b, c) +writeRef3 r1 r2 r3 = from3 ^>> writeRef r1 *** writeRef2 r2 r3 >>^ to3 + +writeRef3_ :: Ref a -> Ref b -> Ref c -> Trans (a, b, c) () +writeRef3_ r1 r2 r3 = writeRef3 r1 r2 r3 >>^ const () + +---------------------------------------------------------------------------- +-- Named parameters + +type ParamTrans i a = Trans (i, a) a + +parameter1 :: Ref a -> (a -> b -> Maybe b) -> ParamTrans a b +parameter1 r1 f = first (transRef r1) >>> makeTrans (uncurry f) + +parameter2 :: Ref a -> Ref b -> (a -> b -> c -> Maybe c) -> ParamTrans (a, b) c +parameter2 r1 r2 f = first (transRef r1 *** transRef r2) >>> makeTrans (uncurry (uncurry f)) + +parameter3 :: Ref a -> Ref b -> Ref c -> (a -> b -> c -> d -> Maybe d) -> ParamTrans (a, b, c) d +parameter3 r1 r2 r3 f = first (from3 ^>> t >>^ to3) >>> makeTrans (uncurry (\(a, b, c) -> f a b c)) + where + t = transRef r1 *** (transRef r2 *** transRef r3) + +transRef :: Ref a -> Trans a a +transRef r = (identity &&& readRefMaybe r) >>> uncurry fromMaybe ^>> writeRef r + +supplyParameters :: ParamTrans b a -> Trans a b -> Transformation (Context a) +supplyParameters f g = transLiftContextIn $ + transUseEnvironment (g &&& identity) >>> first f + +----------------------------------------------------------------- +-- helpers + +from3 :: (a, b, c) -> (a, (b, c)) +from3 (a, b, c) = (a, (b, c)) + +to3 :: (a, (b, c)) -> (a, b, c) +to3 (a, (b, c)) = (a, b, c) + +uncurry3 :: (a -> b -> c -> d) -> (a, b, c) -> d +uncurry3 f (a, b, c) = f a b c
src/Ideas/Common/Rule/Recognizer.hs view
@@ -14,13 +14,11 @@ ( -- * data type and type class Recognizable(..), Recognizer -- * Constructor functions - , makeRecognizer, makeRecognizerEnvMonad, makeRecognizerTrans + , makeRecognizer, makeRecognizerTrans ) where -import Control.Monad import Data.Maybe import Ideas.Common.Environment -import Ideas.Common.Rule.EnvironmentMonad import Ideas.Common.Rule.Transformation import Ideas.Common.View @@ -58,10 +56,8 @@ --- Constructor functions makeRecognizer :: (a -> a -> Bool) -> Recognizer a -makeRecognizer eq = makeRecognizerEnvMonad $ \a b -> guard (eq a b) - -makeRecognizerEnvMonad :: (a -> a -> EnvMonad ()) -> Recognizer a -makeRecognizerEnvMonad = makeRecognizerTrans . makeTrans . uncurry +makeRecognizer eq = makeRecognizerTrans $ transMaybe $ \(x, y) -> + if eq x y then Just () else Nothing makeRecognizerTrans :: Trans (a, a) () -> Recognizer a makeRecognizerTrans = R
src/Ideas/Common/Rule/Transformation.hs view
@@ -19,46 +19,48 @@ Transformation, Trans -- * Constructor functions , MakeTrans(..) - , transPure, transMaybe, transList, transEnvMonad - , transRewrite, transRef + , transPure, transMaybe, transList, transGuard, transRewrite + -- * Reading and writing (with references) + , readRef, readRefDefault, readRefMaybe + , writeRef, writeRef_, writeRefMaybe -- * Lifting transformations , transUseEnvironment , transLiftView, transLiftViewIn , transLiftContext, transLiftContextIn - , makeTransLiftContext, makeTransLiftContext_ -- * Using transformations , transApply, transApplyWith - , getRewriteRules, isZeroTrans + , getRewriteRules ) where +import Control.Applicative import Control.Arrow import Data.Maybe -import Data.Typeable import Ideas.Common.Classes import Ideas.Common.Context import Ideas.Common.Environment import Ideas.Common.Rewriting -import Ideas.Common.Rule.EnvironmentMonad -import Ideas.Common.Utils import Ideas.Common.View +import Ideas.Utils.Prelude import qualified Control.Category as C ----------------------------------------------------------- --- Trans data type and instances +type Transformation a = Trans a a + data Trans a b where Zero :: Trans a b List :: (a -> [b]) -> Trans a b Rewrite :: RewriteRule a -> Trans a a - EnvMonad :: (a -> EnvMonad b) -> Trans a b - Ref :: Typeable a => Ref a -> Trans a a UseEnv :: Trans a b -> Trans (a, Environment) (b, Environment) (:>>:) :: Trans a b -> Trans b c -> Trans a c (:**:) :: Trans a c -> Trans b d -> Trans (a, b) (c, d) (:++:) :: Trans a c -> Trans b d -> Trans (Either a b) (Either c d) - Apply :: Trans (Trans a b, a) b Append :: Trans a b -> Trans a b -> Trans a b + ReadRefM :: Ref a -> Trans x (Maybe a) + WriteRefM :: Ref a -> Trans (Maybe a) () + instance C.Category Trans where id = arr id (.) = flip (:>>:) @@ -80,15 +82,21 @@ left f = f :++: identity right f = identity :++: f -instance ArrowApply Trans where - app = Apply - instance Monoid (Trans a b) where mempty = zeroArrow mappend = (<+>) -type Transformation a = Trans a a +instance Functor (Trans a) where + fmap f t = t >>^ f +instance Applicative (Trans a) where + pure = transPure . const + s <*> t = (s &&& t) >>^ uncurry ($) + +instance Alternative (Trans a) where + empty = zeroArrow + (<|>) = (<+>) + ----------------------------------------------------------- --- Constructor functions @@ -103,9 +111,6 @@ instance MakeTrans [] where makeTrans = transList -instance MakeTrans EnvMonad where - makeTrans = transEnvMonad - transPure :: (a -> b) -> Trans a b transPure f = transList (return . f) @@ -115,17 +120,35 @@ transList :: (a -> [b]) -> Trans a b transList = List -transEnvMonad :: (a -> EnvMonad b) -> Trans a b -transEnvMonad = EnvMonad +transGuard :: (a -> Bool) -> Trans a a +transGuard p = transMaybe $ \x -> if p x then Just x else Nothing transRewrite :: RewriteRule a -> Trans a a transRewrite = Rewrite -transRef :: Typeable a => Ref a -> Trans a a -transRef = Ref +----------------------------------------------------------- +-- Reading and writing (with references) +readRef :: Ref a -> Trans x a +readRef r = readRefMaybe r >>> transMaybe id + +readRefDefault :: a -> Ref a -> Trans x a +readRefDefault a r = readRefMaybe r >>^ fromMaybe a + +readRefMaybe :: Ref a -> Trans x (Maybe a) +readRefMaybe = ReadRefM + +writeRef :: Ref a -> Trans a a +writeRef r = (identity &&& writeRef_ r) >>^ fst + +writeRef_ :: Ref a -> Trans a () +writeRef_ r = Just ^>> writeRefMaybe r + +writeRefMaybe :: Ref a -> Trans (Maybe a) () +writeRefMaybe = WriteRefM + ----------------------------------------------------------- ---- Lifting transformations +-- Lifting transformations transUseEnvironment :: Trans a b -> Trans (a, Environment) (b, Environment) transUseEnvironment = UseEnv @@ -134,7 +157,7 @@ transLiftView v = transLiftViewIn (v &&& identity) transLiftViewIn :: View a (b, c) -> Transformation b -> Transformation a -transLiftViewIn v f = makeTrans (match v) >>> first f >>> arr (build v) +transLiftViewIn v f = makeTrans (match v) >>> first f >>^ build v transLiftContext :: Transformation a -> Transformation (Context a) transLiftContext = transLiftContextIn . transUseEnvironment @@ -145,14 +168,6 @@ f (a, c) = ((a, environment c), c) g ((a, env), c) = (a, setEnvironment env c) --- | Overloaded variant of @transLiftContext@ -makeTransLiftContext :: MakeTrans f => (a -> f a) -> Transformation (Context a) -makeTransLiftContext = transLiftContext . makeTrans - --- | Overloaded variant of @transLiftContext@; ignores result -makeTransLiftContext_ :: MakeTrans f => (a -> f ()) -> Transformation (Context a) -makeTransLiftContext_ f = transLiftContext (identity &&& makeTrans f >>> arr fst) - ----------------------------------------------------------- --- Using transformations @@ -165,21 +180,18 @@ Zero -> [] List f -> [ (b, env) | b <- f a ] Rewrite r -> [ (b, env) | b <- applyAll r a ] - EnvMonad f -> runEnvMonad (f a) env - Ref ref -> case ref ? env of - Just b -> [(b, env)] - Nothing -> [(a, insertRef ref a env)] UseEnv f -> do (b, envb) <- transApplyWith (snd a) f (fst a) return ((b, envb), env) f :>>: g -> do (b, env1) <- transApplyWith env f a (c, env2) <- transApplyWith env1 g b return (c, env2) f :**: g -> do (b, env1) <- transApplyWith env f (fst a) - (c, env2) <- transApplyWith env g (snd a) - return ((b, c), env2 `mappend` env1) + (c, env2) <- transApplyWith env1 g (snd a) + return ((b, c), env2) f :++: g -> either (make Left f) (make Right g) a - Apply -> uncurry (transApplyWith env) a Append f g -> transApplyWith env f a ++ transApplyWith env g a + ReadRefM r -> [(r ? env, env)] + WriteRefM r -> [((), maybe (deleteRef r) (insertRef r) a env)] where make :: (b -> c) -> Trans a b -> a -> [(c, Environment)] make f g = map (mapFirst f) . transApplyWith env g @@ -193,27 +205,17 @@ instance HasRefs (Trans a b) where allRefs trans = case trans of - Ref r -> [Some r] - EnvMonad f -> envMonadFunctionRefs f - _ -> descendTrans allRefs trans - -isZeroTrans :: Trans a b -> Bool -isZeroTrans = or . rec - where - rec :: Trans a b -> [Bool] - rec trans = - case trans of - Zero -> [True] - Append f g -> [isZeroTrans f && isZeroTrans g] - _ -> descendTrans rec trans + ReadRefM r -> [Some r] + WriteRefM r -> [Some r] + _ -> descendTrans allRefs trans -- General recursion function (existentially quantified) descendTrans :: Monoid m => (forall x y . Trans x y -> m) -> Trans a b -> m descendTrans make trans = case trans of - UseEnv f -> make f - f :>>: g -> make f `mappend` make g - f :**: g -> make f `mappend` make g - f :++: g -> make f `mappend` make g - Append f g -> make f `mappend` make g - _ -> mempty+ UseEnv f -> make f + f :>>: g -> make f `mappend` make g + f :**: g -> make f `mappend` make g + f :++: g -> make f `mappend` make g + Append f g -> make f `mappend` make g + _ -> mempty
src/Ideas/Common/Strategy.hs view
@@ -31,7 +31,7 @@ , many, many1, replicate, option -- ** Negation and greedy combinators , check, not, repeat, repeat1, try, (|>), (./.) - , exhaustive, while, until + , exhaustive, while, until, dynamic -- ** Graph , DependencyGraph, dependencyGraph -- ** Traversal combinators
src/Ideas/Common/Strategy/Abstract.hs view
@@ -33,22 +33,22 @@ ) where import Data.Foldable (toList) +import Data.Maybe import Ideas.Common.Classes -import Ideas.Common.CyclicTree hiding (label) import Ideas.Common.Derivation import Ideas.Common.Environment import Ideas.Common.Id import Ideas.Common.Rewriting (RewriteRule) import Ideas.Common.Rule import Ideas.Common.Strategy.Choice +import Ideas.Common.Strategy.CyclicTree hiding (label) import Ideas.Common.Strategy.Prefix import Ideas.Common.Strategy.Process import Ideas.Common.Strategy.Sequence (Sequence(..), ready) import Ideas.Common.Strategy.StrategyTree -import Ideas.Common.Strategy.Symbol import Ideas.Common.View import Prelude hiding (sequence) -import qualified Ideas.Common.CyclicTree as Tree +import qualified Ideas.Common.Strategy.CyclicTree as Tree ----------------------------------------------------------- --- Strategy data-type @@ -99,11 +99,14 @@ toStrategy (LS info (S t)) = S (Tree.label info t) instance IsStrategy Rule where - toStrategy = S . leaf + toStrategy = S . leaf . LeafRule instance IsStrategy RewriteRule where toStrategy = toStrategy . ruleRewrite +instance IsStrategy Dynamic where + toStrategy = S . leaf . LeafDyn + liftS :: IsStrategy f => (Strategy a -> Strategy a) -> f a -> Strategy a liftS f = f . toStrategy @@ -184,20 +187,23 @@ -- | Returns a list of all major rules that are part of a labeled strategy rulesInStrategy :: IsStrategy f => f a -> [Rule a] -rulesInStrategy s = [ r | r <- toList (toStrategyTree s), isMajor r ] +rulesInStrategy s = concatMap f (toList (toStrategyTree s)) + where + f (LeafRule r) | isMajor r = [r] + f _ = [] instance LiftView LabeledStrategy where - liftViewIn = mapRules . liftViewIn + liftViewIn v (LS n s) = LS n (liftViewIn v s) instance LiftView Strategy where - liftViewIn = mapRulesS . liftViewIn + liftViewIn v = S . fmap (liftViewIn v) . toStrategyTree -- | Apply a function to all the rules that make up a labeled strategy -mapRules :: (Rule a -> Rule b) -> LabeledStrategy a -> LabeledStrategy b +mapRules :: (Rule a -> Rule a) -> LabeledStrategy a -> LabeledStrategy a mapRules f (LS n s) = LS n (mapRulesS f s) -mapRulesS :: (Rule a -> Rule b) -> Strategy a -> Strategy b -mapRulesS f = S . fmap f . unS +mapRulesS :: (Rule a -> Rule a) -> Strategy a -> Strategy a +mapRulesS = onStrategyTree . mapRulesInTree -- | Use a function as do-after hook for all rules in a labeled strategy, but -- also use the function beforehand @@ -219,12 +225,8 @@ onStrategyTree :: IsStrategy f => (StrategyTree a -> StrategyTree a) -> f a -> Strategy a onStrategyTree f = S . f . toStrategyTree -getProcess :: IsStrategy f => f a -> Process (Rule a) -getProcess = foldUnwind emptyAlg - { fNode = fromNary . combinator - , fLeaf = single - , fLabel = \l p -> enterRule l ~> p .*. (exitRule l ~> done) - } . toStrategyTree +getProcess :: IsStrategy f => f a -> Process (Leaf a) +getProcess = treeToProcess . toStrategyTree -------------------------
src/Ideas/Common/Strategy/Combinators.hs view
@@ -18,13 +18,14 @@ import Data.Graph import Data.List ((\\)) import Data.Maybe -import Ideas.Common.CyclicTree hiding (label) import Ideas.Common.Id +import Ideas.Common.Rewriting (IsTerm) import Ideas.Common.Rule import Ideas.Common.Strategy.Abstract +import Ideas.Common.Strategy.CyclicTree hiding (label) import Ideas.Common.Strategy.Process import Ideas.Common.Strategy.StrategyTree -import Ideas.Common.Utils (fst3, thd3) +import Ideas.Utils.Prelude (fst3, thd3) import Prelude hiding (not, repeat, fail, sequence) import qualified Ideas.Common.Strategy.Choice as Choice import qualified Ideas.Common.Strategy.Derived as Derived @@ -132,7 +133,7 @@ -- strategy only succeeds if this is not the case (otherwise it fails). not :: IsStrategy f => f a -> Strategy a not = decl1 $ "not" .=. Unary (\x -> - Sequence.single $ checkRule "core.not" $ null . runProcess x) + Sequence.single $ LeafRule $ checkRule "core.not" $ null . runProcess x) -- | Repeat a strategy zero or more times (greedy version of 'many') repeat :: IsStrategy f => f a -> Strategy a @@ -168,6 +169,10 @@ -- | Apply the strategies from the list exhaustively (until this is no longer possible) exhaustive :: IsStrategy f => [f a] -> Strategy a exhaustive = declN $ "exhaustive" .=. Nary Derived.exhaustive + +-- | The structure of a dynamic strategy depends on the current term +dynamic :: (IsId n, IsStrategy f, IsTerm a) => n -> (a -> f a) -> Strategy a +dynamic n f = toStrategy $ makeDynamic n (toStrategyTree . f) -- Graph to strategy ----------------------
src/Ideas/Common/Strategy/Configuration.hs view
@@ -23,17 +23,17 @@ import Data.Char import Ideas.Common.Classes -import Ideas.Common.CyclicTree hiding (label) import Ideas.Common.Id import Ideas.Common.Rule import Ideas.Common.Strategy.Abstract import Ideas.Common.Strategy.Choice +import Ideas.Common.Strategy.CyclicTree hiding (label) import Ideas.Common.Strategy.Derived (repeat1) import Ideas.Common.Strategy.Process hiding (fold) import Ideas.Common.Strategy.Sequence import Ideas.Common.Strategy.StrategyTree import Ideas.Common.Strategy.Symbol -import qualified Ideas.Common.CyclicTree as Tree +import qualified Ideas.Common.Strategy.CyclicTree as Tree --------------------------------------------------------------------- -- Types and constructors @@ -48,7 +48,7 @@ mconcat xs = Cfg [ y | Cfg ys <- xs, y <- ys ] mappend (Cfg xs) (Cfg ys) = Cfg (xs ++ ys) -data ConfigLocation = ByName Id +newtype ConfigLocation = ByName Id instance Show ConfigLocation where show (ByName a) = show a @@ -137,13 +137,13 @@ removeDecl = "removed" .=. Unary (const empty) collapseDecl :: Decl Unary -collapseDecl = "collapsed" .=. Unary (\a -> - case firsts a of - [(r, _)] -> maybe empty (`collapseWith` a) (isEnterRule r) - _ -> empty) +collapseDecl = "collapsed" .=. Unary f where + f a = case firsts a of + [(LeafRule r, _)] -> maybe empty (`collapseWith` a) (isEnterRule r) + _ -> empty collapseWith l = - single . makeRule l . runProcess + single . LeafRule . makeRule l . runProcess hideDecl :: Decl Unary hideDecl = "hidden" .=. Unary (fmap minor)
+ src/Ideas/Common/Strategy/CyclicTree.hs view
@@ -0,0 +1,217 @@+----------------------------------------------------------------------------- +-- Copyright 2016, Ideas project team. This file is distributed under the +-- terms of the Apache License 2.0. For more information, see the files +-- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution. +----------------------------------------------------------------------------- +-- | +-- Maintainer : bastiaan.heeren@ou.nl +-- Stability : provisional +-- Portability : portable (depends on ghc) +-- +----------------------------------------------------------------------------- + +module Ideas.Common.Strategy.CyclicTree + ( -- * Data type + CyclicTree + -- * Constructor functions + , node, node0, node1, node2, leaf, label + -- * Querying + , isNode, isLeaf, isLabel + -- * Replace functions + , replaceNode, replaceLeaf, replaceLabel, shrinkTree + -- * Fold and algebra + , fold, foldUnwind + , CyclicTreeAlg, fNode, fLeaf, fLabel, fRec, fVar + , emptyAlg, monoidAlg + ) where + +import Control.Monad +import Data.List (intercalate) +import Ideas.Common.Classes +import Ideas.Common.Id +import Test.QuickCheck hiding (label) + +-------------------------------------------------------------- +-- Data type + +data CyclicTree a b + = Node a [CyclicTree a b] + | Leaf b + | Label Id (CyclicTree a b) + | Rec Int (CyclicTree a b) + | Var Int + +instance (Show a, Show b) => Show (CyclicTree a b) where + show = fold Alg + { fNode = \a xs -> show a ++ par xs + , fLeaf = show + , fLabel = \l s -> show l ++ ":" ++ s + , fRec = \n s -> '#' : show n ++ "=" ++ s + , fVar = \n -> '#' : show n + } + +instance BiFunctor CyclicTree where + biMap f g = fold idAlg {fNode = Node . f, fLeaf = Leaf . g} + +instance Functor (CyclicTree d) where + fmap = mapSecond + +instance Applicative (CyclicTree d) where + pure = leaf + p <*> q = fold idAlg {fLeaf = (<$> q)} p + +instance Monad (CyclicTree d) where + return = leaf + (>>=) = flip replaceLeaf + +instance Foldable (CyclicTree d) where + foldMap f = fold monoidAlg {fLeaf = f} + +instance Traversable (CyclicTree d) where + traverse f = fold emptyAlg + { fNode = \a -> fmap (node a) . sequenceA + , fLeaf = fmap leaf . f + , fLabel = fmap . label + , fRec = fmap . Rec + , fVar = pure . Var + } + +instance Fix (CyclicTree a b) where + fix f = Rec n (f (Var n)) + where + vs = vars (f (Var (-1))) + n = maximum (-1 : vs) + 1 + +instance (Arbitrary a, Arbitrary b) => Arbitrary (CyclicTree a b) where + arbitrary = sized arbTree + shrink = shrinkTree + +arbTree :: (Arbitrary a, Arbitrary b) => Int -> Gen (CyclicTree a b) +arbTree = rec 0 + where + rec vi 0 = frequency $ + (3, leaf <$> arbitrary) + : [ (1, elements (map Var [1..vi])) | vi > 0 ] + rec vi n = frequency + [ (3, node <$> arbitrary <*> ms) + , (2, rec vi 0) + , (1, label <$> genId <*> m) + , (1, Rec (vi+1) <$> rec (vi+1) (n `div` 2)) + ] + where + m = rec vi (n `div` 2) + genId = elements [ newId [c] | c <- ['A' .. 'Z']] + ms = choose (0, 3) >>= \i -> replicateM i m + +shrinkTree :: CyclicTree a b -> [CyclicTree a b] +shrinkTree tree = + case tree of + Node a ts -> ts ++ map (node a) (shrinkTrees ts) + Label l t -> t : map (Label l) (shrinkTree t) + Rec n t -> map (Rec n) (shrinkTree t) + _ -> [] + +-- shrink exactly one tree +shrinkTrees :: [CyclicTree a b] -> [[CyclicTree a b]] +shrinkTrees [] = [] +shrinkTrees (t:ts) = map (:ts) (shrinkTree t) ++ map (t:) (shrinkTrees ts) + +-- local helpers +par :: [String] -> String +par xs | null xs = "" + | otherwise = "(" ++ intercalate ", " xs ++ ")" + +vars :: CyclicTree a b -> [Int] +vars = fold monoidAlg {fVar = return} + +-------------------------------------------------------------- +-- Constructor functions + +node :: a -> [CyclicTree a b] -> CyclicTree a b +node = Node + +node0 :: a -> CyclicTree a b +node0 a = node a [] + +node1 :: a -> CyclicTree a b -> CyclicTree a b +node1 a x = node a [x] + +node2 :: a -> CyclicTree a b -> CyclicTree a b -> CyclicTree a b +node2 a x y = node a [x, y] + +leaf :: b -> CyclicTree a b +leaf = Leaf + +label :: IsId n => n -> CyclicTree a b -> CyclicTree a b +label = Label . newId + +-------------------------------------------------------------- +-- Querying + +isNode :: CyclicTree a b -> Maybe (a, [CyclicTree a b]) +isNode (Node a xs) = Just (a, xs) +isNode _ = Nothing + +isLeaf :: CyclicTree a b -> Maybe b +isLeaf (Leaf b) = Just b +isLeaf _ = Nothing + +isLabel :: CyclicTree a b -> Maybe (Id, CyclicTree a b) +isLabel (Label l t) = Just (l, t) +isLabel _ = Nothing + +-------------------------------------------------------------- +-- Replace functions + +replaceNode :: (a -> [CyclicTree a b] -> CyclicTree a b) -> CyclicTree a b -> CyclicTree a b +replaceNode f = fold idAlg {fNode = f} + +replaceLabel :: (Id -> CyclicTree a b -> CyclicTree a b) -> CyclicTree a b -> CyclicTree a b +replaceLabel f = fold idAlg {fLabel = f} + +replaceLeaf :: (b -> CyclicTree a c) -> CyclicTree a b -> CyclicTree a c +replaceLeaf f = fold idAlg {fLeaf = f} + +-------------------------------------------------------------- +-- Fold and algebra + +fold :: CyclicTreeAlg a b t -> CyclicTree a b -> t +fold alg = rec + where + rec (Node a ts) = fNode alg a (map rec ts) + rec (Leaf b) = fLeaf alg b + rec (Label l t) = fLabel alg l (rec t) + rec (Rec n t) = fRec alg n (rec t) + rec (Var n) = fVar alg n + +foldUnwind :: CyclicTreeAlg a b t -> CyclicTree a b -> t +foldUnwind alg = start . fold Alg + { fNode = \a fs sub -> fNode alg a (map ($ sub) fs) + , fLeaf = \b _ -> fLeaf alg b + , fLabel = \l f sub -> fLabel alg l (f sub) + , fRec = \n f sub -> let this = f (extend n this sub) + in this + , fVar = \n sub -> sub n + } + where + start f = f (error "foldUnwind: unbound var") + extend n a sub i + | i == n = a + | otherwise = sub i + +data CyclicTreeAlg a b t = Alg + { fNode :: a -> [t] -> t + , fLeaf :: b -> t + , fLabel :: Id -> t -> t + , fRec :: Int -> t -> t + , fVar :: Int -> t + } + +idAlg :: CyclicTreeAlg a b (CyclicTree a b) +idAlg = Alg Node Leaf Label Rec Var + +emptyAlg :: CyclicTreeAlg a b t +emptyAlg = let f = error "emptyAlg: uninitialized" in Alg f f f f f + +monoidAlg :: Monoid m => CyclicTreeAlg a b m +monoidAlg = Alg (const mconcat) mempty (const id) (const id) mempty
src/Ideas/Common/Strategy/Derived.hs view
@@ -30,29 +30,19 @@ import Prelude hiding (sequence, replicate, repeat) import qualified Prelude -split :: (AtomicSymbol a, Choice b) - => (Process a -> Process a -> b) -> b -> Process a -> b -split op = split2 (op . single) op - --- Specialized version of split that also takes an operator for the special case --- that the left part of the split is a single symbol. -split2 :: (AtomicSymbol a, Choice b) - => (a -> Process a -> b) -> (Process a -> Process a -> b) -> b -> Process a -> b -split2 op1 op2 = withMenu f +split :: AtomicSymbol a => (a -> Bool) -> (Process a -> Process a) -> Process a -> Process a +split skipCond cont = rec (0 :: Int) where - f a | a == atomicOpen = rec (op2 . (a ~>)) 1 - | otherwise = op1 a - - rec acc n - | n == 0 = acc done - | otherwise = withMenu g empty + rec n = withMenu op empty where - g a = rec (acc . (a ~>)) (pm a n) - - pm :: AtomicSymbol a => a -> Int -> Int - pm a | a == atomicOpen = succ - | a == atomicClose = pred - | otherwise = id + op a = a ~> rest + where + next | a == atomicOpen = n+1 + | a == atomicClose = n-1 + | otherwise = n + rest | skipCond a = rec next + | next > 0 = rec next + | otherwise = cont -- atomic prefix (!*>) :: AtomicSymbol a => Process a -> Process a -> Process a @@ -81,21 +71,7 @@ where bothAreDone = withMenu stop2 . withMenu stop2 done stop2 _ _ = empty - --- left-interleaving -(%>>) :: (AtomicSymbol a, LabelSymbol a) => Process a -> Process a -> Process a -p %>> q = rec (0 :: Int) p - where - rec n = withMenu op empty - where - op a = a ~> rest - where - next | a == atomicOpen = n+1 - | a == atomicClose = n-1 - | otherwise = n - rest | isEnterSymbol a = rec next - | next > 0 = rec next - | otherwise = (<%> q) + r %>> s = split isEnterSymbol (<%> s) r -- | Allows all permutations of the list permute :: (Choice a, Sequence a) => [a] -> a @@ -109,17 +85,13 @@ -- Alternate combinator (<@>) :: AtomicSymbol a => Process a -> Process a -> Process a -p0 <@> q0 = rec q0 p0 +p <@> q = bothOk p q .|. (p @>> q) where - rec q = let op b r = b .*. rec r q - in split op (bothOk q) - bothOk = withMenu (\_ _ -> empty) done + bothOk = withMenu (\_ _ -> empty) done + r @>> s = split (const False) (s <@>) r inits :: AtomicSymbol a => Process a -> Process a -inits = rec - where - rec p = done .|. split op empty p - op x = (x .*.) . rec +inits p = done .|. split (const False) inits p many :: (Sequence a, Fix a, Choice a) => a -> a many s = fix $ \x -> done .|. (s .*. x)
src/Ideas/Common/Strategy/Location.hs view
@@ -18,9 +18,9 @@ ) where import Data.Maybe -import Ideas.Common.CyclicTree import Ideas.Common.Id import Ideas.Common.Strategy.Abstract +import Ideas.Common.Strategy.CyclicTree ----------------------------------------------------------- --- Strategy locations
src/Ideas/Common/Strategy/Prefix.hs view
@@ -27,15 +27,18 @@ , Path, emptyPath, readPath, readPaths ) where -import Control.Monad +import Data.Char import Data.List (intercalate) +import Data.Maybe import Ideas.Common.Classes import Ideas.Common.Environment +import Ideas.Common.Rewriting.Term import Ideas.Common.Rule import Ideas.Common.Strategy.Choice import Ideas.Common.Strategy.Process import Ideas.Common.Strategy.Sequence -import Ideas.Common.Utils (splitsWithElem, readM) +import Ideas.Common.Strategy.StrategyTree +import Ideas.Utils.Prelude (splitsWithElem, readM) -------------------------------------------------------------------------------- -- Prefix datatype @@ -72,30 +75,41 @@ noPrefix = Prefix [] empty -- | Make a prefix from a core strategy and a start term. -makePrefix :: Process (Rule a) -> a -> Prefix a +makePrefix :: Process (Leaf a) -> a -> Prefix a makePrefix = snd . replayProcess emptyPath -- | Construct a prefix by replaying a path in a core strategy: the third -- argument is the current term. -replayProcess :: Path -> Process (Rule a) -> ([Rule a], a -> Prefix a) -replayProcess (Path is) = replay [] is +replayProcess :: Path -> Process (Leaf a) -> ([Rule a], a -> Prefix a) +replayProcess (Path is) = fromMaybe ([], const noPrefix) . replay [] is where - replay acc [] p = (reverse acc, createPrefix p) - replay acc (n:ns) p = - case getByIndex n (menu p) of - Just (a, r) -> replay (a:acc) ns r - _ -> ([], const noPrefix) + replay acc path p = + case path of + [] -> return (reverse acc, createPrefix p) + Input _:_ -> Nothing + Index n:ns -> do + (leaf, q) <- getByIndex n (menu p) + case (leaf, ns) of + (LeafRule r, _) -> replay (r:acc) ns q + (LeafDyn d, Input t:ns2) -> do + a <- dynamicFromTerm d t + replay acc ns2 (treeToProcess a .*. q) + _ -> Nothing createPrefix p = Prefix [Path is] . flip (rec []) p rec ns a = cut . onMenuWithIndex f doneMenu . menu where - f n r p = choice + f n (LeafDyn d) p = fromMaybe empty $ do + t <- dynamicToTerm d a + s <- dynamicFromTerm d t + return (rec (Input t:Index n:ns) a (treeToProcess s .*. p)) + f n (LeafRule r) p = choice [ r ?~> (b, env, mk b) | (b, env) <- transApply (transformation r) a ] where - ms = n:ns + ms = Index n:ns path = Path (is ++ reverse ms) mk b = Prefix [path] (rec ms b p) @@ -153,19 +167,33 @@ -- Path -- | A path encodes a location in a strategy. Paths are represented as a list --- of integers. -newtype Path = Path [Int] +-- of integers and terms (the latter act as input for the dynamic strategies). +newtype Path = Path [PathItem] deriving Eq +data PathItem = Index Int | Input Term + deriving Eq + +instance Show PathItem where + show (Index n) = show n + show (Input t) = show t + +instance Read PathItem where + readsPrec n s = + case dropWhile isSpace s of + s2@(c:_) | isDigit c -> map (mapFirst Index) (readsPrec n s2) + s2 -> map (mapFirst Input) (readsPrec n s2) + instance Show Path where show (Path is) = show is + showList = (++) . intercalate ";" . map show -- | The empty path. emptyPath :: Path emptyPath = Path [] readPath :: Monad m => String -> m Path -readPath = liftM Path . readM +readPath = fmap Path . readM readPaths :: Monad m => String -> m [Path] readPaths = mapM readPath . splitsWithElem ';'
src/Ideas/Common/Strategy/StrategyTree.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE RankNTypes, ExistentialQuantification #-} ----------------------------------------------------------------------------- -- Copyright 2016, Ideas project team. This file is distributed under the -- terms of the Apache License 2.0. For more information, see the files @@ -16,29 +16,90 @@ module Ideas.Common.Strategy.StrategyTree ( -- * StrategyTree type synonym - StrategyTree + StrategyTree, Leaf(..), treeToProcess, mapRulesInTree -- * Declarations (named combinators) , Decl, Combinator, associative, isAssociative, combinator , (.=.), applyDecl + -- * Dynamic strategies + , Dynamic, makeDynamic, dynamicToTerm, dynamicTree, dynamicFromTerm -- * Arities , Arity(..), Nullary(..), Unary(..), Binary(..), Nary(..) ) where +import Control.Monad import Data.Function import Data.Maybe -import Ideas.Common.CyclicTree +import Ideas.Common.Classes import Ideas.Common.Id +import Ideas.Common.Rewriting.Term (Term, IsTerm(..)) import Ideas.Common.Rule import Ideas.Common.Strategy.Choice +import Ideas.Common.Strategy.CyclicTree import Ideas.Common.Strategy.Process +import Ideas.Common.Strategy.Sequence +import Ideas.Common.Strategy.Symbol import Ideas.Common.View infix 1 .=. ------------------------------------------------------------------------------ -type StrategyTree a = CyclicTree (Decl Nary) (Rule a) +type StrategyTree a = CyclicTree (Decl Nary) (Leaf a) +data Leaf a = LeafRule (Rule a) + | LeafDyn (Dynamic a) + +instance Show (Leaf a) where + show = showId + +instance Eq (Leaf a) where + x == y = getId x == getId y + +instance HasId (Leaf a) where + getId (LeafRule r) = getId r + getId (LeafDyn d) = getId d + changeId f (LeafRule r) = LeafRule (changeId f r) + changeId f (LeafDyn d) = LeafDyn (changeId f d) + +instance AtomicSymbol (Leaf a) where + atomicOpen = LeafRule atomicOpen + atomicClose = LeafRule atomicClose + +instance LabelSymbol (Leaf a) where + isEnterSymbol (LeafRule r) = isEnterSymbol r + isEnterSymbol (LeafDyn _) = False + +instance Minor (Leaf a) where + isMinor (LeafRule r) = isMinor r + isMinor (LeafDyn _) = False + setMinor b (LeafRule r) = LeafRule (setMinor b r) + setMinor _ lf@(LeafDyn _) = lf + +instance Apply Leaf where + applyAll (LeafRule r) a = applyAll r a + applyAll (LeafDyn d) a = applyAll d a + +instance LiftView Leaf where + liftViewIn v (LeafRule r) = LeafRule (liftViewIn v r) + liftViewIn v (LeafDyn d) = LeafDyn (liftViewIn v d) + +treeToProcess :: StrategyTree a -> Process (Leaf a) +treeToProcess = foldUnwind emptyAlg + { fNode = fromNary . combinator + , fLeaf = single + , fLabel = \l p -> LeafRule (enterRule l) ~> p .*. (LeafRule (exitRule l) ~> done) + } + +mapRulesInTree :: (Rule a -> Rule a) -> StrategyTree a -> StrategyTree a +mapRulesInTree f = inTree + where + inTree = fmap inLeaf + + inLeaf (LeafRule r) = LeafRule (f r) + inLeaf (LeafDyn d) = LeafDyn (inDyn d) + + inDyn d = d { dynamicFromTerm = fmap inTree . dynamicFromTerm d } + applyDecl :: Arity f => Decl f -> f (StrategyTree a) applyDecl d = toArity (node (d {combinator = op}) . make) where @@ -54,8 +115,35 @@ ------------------------------------------------------------------------------ -type Combinator f = forall a . f (Process (Rule a)) +data Dynamic a = Dyn + { dynamicId :: Id + , dynamicToTerm :: a -> Maybe Term + , dynamicFromTerm :: Term -> Maybe (StrategyTree a) + } +instance HasId (Dynamic a) where + getId = dynamicId + changeId f d = d { dynamicId = changeId f (dynamicId d) } + +instance Apply Dynamic where + applyAll d a = maybe [] ((`runProcess` a) . treeToProcess) (dynamicTree d a) + +instance LiftView Dynamic where + liftViewIn v d = d + { dynamicToTerm = fmap fst . match v >=> dynamicToTerm d + , dynamicFromTerm = fmap (fmap (liftViewIn v)) . dynamicFromTerm d + } + +makeDynamic :: (IsId n, IsTerm a) => n -> (a -> StrategyTree a) -> Dynamic a +makeDynamic n f = Dyn (newId n) (Just . toTerm) (fmap f . fromTerm) + +dynamicTree :: Dynamic a -> a -> Maybe (StrategyTree a) +dynamicTree d = dynamicToTerm d >=> dynamicFromTerm d + +------------------------------------------------------------------------------ + +type Combinator f = forall a . f (Process (Leaf a)) + data Decl f = C { declId :: Id , combinator :: Combinator f @@ -85,10 +173,10 @@ toArity :: ([a] -> a) -> f a liftIso :: Isomorphism a b -> f a -> f b -data Nullary a = Nullary { fromNullary :: a } -data Unary a = Unary { fromUnary :: a -> a } -data Binary a = Binary { fromBinary :: a -> a -> a } -data Nary a = Nary { fromNary :: [a] -> a } +newtype Nullary a = Nullary { fromNullary :: a } +newtype Unary a = Unary { fromUnary :: a -> a } +newtype Binary a = Binary { fromBinary :: a -> a -> a } +newtype Nary a = Nary { fromNary :: [a] -> a } instance Arity Nullary where listify (Nullary a) [] = Just a
@@ -37,7 +37,7 @@ import Data.Maybe import Ideas.Common.Traversal.Iterator import Ideas.Common.Traversal.Utils -import Ideas.Common.Utils.Uniplate +import Ideas.Utils.Uniplate import Test.QuickCheck --------------------------------------------------------------- @@ -69,7 +69,7 @@ childnr :: a -> Int location :: a -> Location -- default definitions - downLast = liftM (fixp right) . down + downLast = fmap (fixp right) . down childnr = pred . length . fixpl left location = toLocation . map childnr . drop 1 . reverse . fixpl up @@ -173,7 +173,7 @@ update a = (unwrap a, wrap) instance Navigator a => Iterator (PreOrder a) where - previous = liftWrapper ((liftM rightMostLeaf . left) >|< up) + previous = liftWrapper ((fmap rightMostLeaf . left) >|< up) next = let rec = right >|< (up >=> rec) in liftWrapper (down >|< rec) first = mapWrapper top @@ -249,10 +249,10 @@ instance Navigator a => Iterator (Leafs a) where previous = liftWrapper $ let rec = left >|< (up >=> rec) - in liftM rightMostLeaf . rec + in fmap rightMostLeaf . rec next = liftWrapper $ let rec = right >|< (up >=> rec) - in liftM leftMostLeaf . rec + in fmap leftMostLeaf . rec first = mapWrapper (leftMostLeaf . top) final = mapWrapper (rightMostLeaf . top) @@ -300,8 +300,8 @@ } instance Iterator (StrIterator a) where - next (SI n a) = liftM (SI (n+1)) $ searchNext ok a - previous (SI n a) = liftM (SI (n-1)) $ searchPrevious ok a + next (SI n a) = SI (n+1) <$> searchNext ok a + previous (SI n a) = SI (n-1) <$> searchPrevious ok a first (SI _ a) = SI 0 $ safe (searchForward ok) (first a) final (SI _ a) = finalSI $ safe (searchBackward ok) (final a) position = posSI @@ -350,8 +350,8 @@ down = downWith focusM downLast = downWith lastStrIterator - left (U fs a) = liftM (U fs) (previous a) - right (U fs a) = liftM (U fs) (next a) + left (U fs a) = U fs <$> previous a + right (U fs a) = U fs <$> next a childnr (U _ a) = position a @@ -364,7 +364,7 @@ unfocus = current . top instance (Arbitrary a, Uniplate a) => Arbitrary (UniplateNavigator a) where - arbitrary = liftM focus arbitrary >>= genNav + arbitrary = fmap focus arbitrary >>= genNav where genNav a = case map genNav (downs a) of @@ -373,7 +373,7 @@ downWith :: Uniplate a => (Str a -> Maybe (StrIterator a)) -> UniplateNavigator a -> Maybe (UniplateNavigator a) -downWith make (U fs a) = liftM (U (f:fs)) (make cs) +downWith make (U fs a) = U (f:fs) <$> make cs where (cs, g) = uniplate (current a) f = (`replace` a) . g . unfocus
src/Ideas/Common/Traversal/Tests.hs view
@@ -20,8 +20,8 @@ import Ideas.Common.Traversal.Iterator import Ideas.Common.Traversal.Navigator import Ideas.Common.Traversal.Utils -import Ideas.Common.Utils.TestSuite -import Ideas.Common.Utils.Uniplate +import Ideas.Utils.TestSuite +import Ideas.Utils.Uniplate import Test.QuickCheck hiding ((===)) testIterator :: (Show a, Eq a, Iterator a) => String -> Gen a -> TestSuite @@ -72,8 +72,8 @@ ] , suite "down/downLast" - [ prop gen "down; rightMost" $ liftM rightMost . down === downLast - , prop gen "downLast; leftMost" $ liftM leftMost . downLast === down + [ prop gen "down; rightMost" $ fmap rightMost . down === downLast + , prop gen "downLast; leftMost" $ fmap leftMost . downLast === down , prop gen "down is leftMost" $ isNothing . (down >=> left) , prop gen "downLast is rightMost" $ isNothing . (downLast >=> right) ] @@ -104,16 +104,16 @@ tests = suite "Iterators" [ testIterator "List" listGen - , testIterator "Mirror" $ liftM makeMirror listGen - , testIterator "Leafs" $ liftM makeLeafs uniGen - , testIterator "PreOrder" $ liftM makePreOrder uniGen - , testIterator "PostOrder" $ liftM makePostOrder uniGen - , testIterator "Horizontal" $ liftM makeHorizontal uniGen - , testIterator "LevelOrder" $ liftM makeLevelOrder uniGen + , testIterator "Mirror" $ makeMirror <$> listGen + , testIterator "Leafs" $ makeLeafs <$> uniGen + , testIterator "PreOrder" $ makePreOrder <$> uniGen + , testIterator "PostOrder" $ makePostOrder <$> uniGen + , testIterator "Horizontal" $ makeHorizontal <$> uniGen + , testIterator "LevelOrder" $ makeLevelOrder <$> uniGen ] <> suite "Navigators" [ testNavigator "Uniplate" uniGen - , testNavigator "Mirror" $ liftM makeMirror uniGen + , testNavigator "Mirror" $ makeMirror <$> uniGen ] _go :: IO ()
src/Ideas/Common/Traversal/Utils.hs view
@@ -46,7 +46,7 @@ changeM = changeG changeG :: (Update f, Monad g) => (a -> g a) -> f a -> g (f a) -changeG f a = liftM (`replace` a) (f (current a)) +changeG f a = (`replace` a) <$> f (current a) --------------------------------------------------------------- -- Focus type class @@ -61,10 +61,10 @@ focusM = Just . focus liftFocus :: Focus a => (Unfocus a -> Maybe (Unfocus a)) -> a -> Maybe a -liftFocus f = liftM focus . f . unfocus +liftFocus f = fmap focus . f . unfocus unliftFocus :: Focus a => (a -> Maybe a) -> Unfocus a -> Maybe (Unfocus a) -unliftFocus f = liftM unfocus . f . focus +unliftFocus f = fmap unfocus . f . focus --------------------------------------------------------------- -- Wrapper type class @@ -74,10 +74,10 @@ unwrap :: f a -> a liftWrapper :: (Monad m, Wrapper f) => (a -> m a) -> f a -> m (f a) -liftWrapper f = liftM wrap . f . unwrap +liftWrapper f = fmap wrap . f . unwrap unliftWrapper :: (Monad m, Wrapper f) => (f a -> m (f a)) -> a -> m a -unliftWrapper f = liftM unwrap . f . wrap +unliftWrapper f = fmap unwrap . f . wrap mapWrapper :: Wrapper f => (a -> a) -> f a -> f a mapWrapper f = wrap . f . unwrap
− src/Ideas/Common/Utils.hs
@@ -1,128 +0,0 @@-{-# LANGUAGE ExistentialQuantification, DeriveDataTypeable #-} ------------------------------------------------------------------------------ --- Copyright 2016, Ideas project team. This file is distributed under the --- terms of the Apache License 2.0. For more information, see the files --- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution. ------------------------------------------------------------------------------ --- | --- Maintainer : bastiaan.heeren@ou.nl --- Stability : provisional --- Portability : portable (depends on ghc) --- --- A collection of general utility functions --- ------------------------------------------------------------------------------ - -module Ideas.Common.Utils - ( Some(..), ShowString(..), readInt, readM - , subsets, isSubsetOf - , cartesian, distinct, allsame - , fixpoint - , splitAtElem, splitsWithElem - , timedSeconds - , fst3, snd3, thd3 - , headM, findIndexM - , elementAt, changeAt, replaceAt - , list - ) where - -import Data.Char -import Data.List -import Data.Typeable -import System.Timeout - -data Some f = forall a . Some (f a) - -data ShowString = ShowString { fromShowString :: String } - deriving (Eq, Ord, Typeable) - -instance Show ShowString where - show = fromShowString - -instance Read ShowString where - readsPrec n s = [ (ShowString x, y) | (x, y) <- readsPrec n s ] - -readInt :: String -> Maybe Int -readInt xs - | null xs = Nothing - | any (not . isDigit) xs = Nothing - | otherwise = Just (foldl' (\a b -> a*10+ord b-48) 0 xs) -- ' - -readM :: (Monad m, Read a) => String -> m a -readM s = case reads s of - [(a, xs)] | all isSpace xs -> return a - _ -> fail ("no read: " ++ s) - -subsets :: [a] -> [[a]] -subsets = foldr op [[]] - where op a xs = xs ++ map (a:) xs - -isSubsetOf :: Eq a => [a] -> [a] -> Bool -isSubsetOf xs ys = all (`elem` ys) xs - -cartesian :: [a] -> [b] -> [(a, b)] -cartesian as bs = [ (a, b) | a <- as, b <- bs ] - -distinct :: Eq a => [a] -> Bool -distinct [] = True -distinct (x:xs) = notElem x xs && distinct xs - -allsame :: Eq a => [a] -> Bool -allsame [] = True -allsame (x:xs) = all (==x) xs - -fixpoint :: Eq a => (a -> a) -> a -> a -fixpoint f = rec . iterate f - where - rec [] = error "Ideas.Common.Utils: empty list" - rec (x:xs) - | x == head xs = x - | otherwise = rec xs - -splitAtElem :: Eq a => a -> [a] -> Maybe ([a], [a]) -splitAtElem c s = - case break (==c) s of - (xs, _:ys) -> Just (xs, ys) - _ -> Nothing - -splitsWithElem :: Eq a => a -> [a] -> [[a]] -splitsWithElem c s = - case splitAtElem c s of - Just (xs, ys) -> xs : splitsWithElem c ys - Nothing -> [s] - -timedSeconds :: Int -> IO a -> IO a -timedSeconds n m = timeout (n * 10^(6 :: Int)) m >>= - maybe (fail ("Timeout after " ++ show n ++ " seconds")) return - -fst3 :: (a, b, c) -> a -fst3 (x, _, _) = x - -snd3 :: (a, b, c) -> b -snd3 (_, x, _) = x - -thd3 :: (a, b, c) -> c -thd3 (_, _, x) = x - --- generalized list functions (results in monad) -headM :: Monad m => [a] -> m a -headM (a:_) = return a -headM _ = fail "headM" - -findIndexM :: Monad m => (a -> Bool) -> [a] -> m Int -findIndexM p = maybe (fail "findIndexM") return . findIndex p - -elementAt :: Monad m => Int -> [a] -> m a -elementAt i = headM . drop i - -changeAt :: Monad m => Int -> (a -> a) -> [a] -> m [a] -changeAt i f as = - case splitAt i as of - (xs, y:ys) -> return (xs ++ f y : ys) - _ -> fail "changeAt" - -replaceAt :: Monad m => Int -> a -> [a] -> m [a] -replaceAt i = changeAt i . const - -list :: b -> ([a] -> b) -> [a] -> b -list b f xs = if null xs then b else f xs
− src/Ideas/Common/Utils/QuickCheck.hs
@@ -1,102 +0,0 @@------------------------------------------------------------------------------ --- Copyright 2016, Ideas project team. This file is distributed under the --- terms of the Apache License 2.0. For more information, see the files --- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution. ------------------------------------------------------------------------------ --- | --- Maintainer : bastiaan.heeren@ou.nl --- Stability : provisional --- Portability : portable (depends on ghc) --- --- Extensions to the QuickCheck library --- ------------------------------------------------------------------------------ - -module Ideas.Common.Utils.QuickCheck - ( module Test.QuickCheck - -- * Data type - , ArbGen, generator, generators - -- * Constructors - , arbGen, constGen, constGens, unaryGen, unaryGens - , unaryArbGen, binaryGen, binaryGens, toArbGen - -- * Frequency combinators - , common, uncommon, rare, changeFrequency - ) where - -import Control.Arrow -import Control.Monad -import Data.Ratio -import Test.QuickCheck - ---------------------------------------------------------- --- @ArbGen@ datatype - -newtype ArbGen a = AG [(Rational, (Int, Gen ([a] -> a)))] - -instance Monoid (ArbGen a) where - mempty = AG mempty - AG xs `mappend` AG ys = AG (xs `mappend` ys) - -generator :: ArbGen a -> Gen a -generator (AG pairs) = sized rec - where - factor = foldr (lcm . denominator . fst) 1 pairs - rec n = frequency (map make (select pairs)) - where - select - | n == 0 = filter ((==0) . fst . snd) - | otherwise = id - make (r, (a, gf)) = - let m = round (fromInteger factor*r) - xs = replicateM a $ rec $ n `div` 2 - in (m, liftM2 ($) gf xs) - -generators :: [ArbGen a] -> Gen a -generators = generator . mconcat - ---------------------------------------------------------- --- Constructors - -arbGen :: Arbitrary b => (b -> a) -> ArbGen a -arbGen f = newGen 0 (liftM (const . f) arbitrary) - -constGen :: a -> ArbGen a -constGen = pureGen 0 . const - -constGens :: [a] -> ArbGen a -constGens = mconcat . map constGen - -unaryGen :: (a -> a) -> ArbGen a -unaryGen f = pureGen 1 (f . head) - -unaryArbGen :: Arbitrary b => (b -> a -> a) -> ArbGen a -unaryArbGen f = newGen 1 $ liftM (\a -> f a . head) arbitrary - -unaryGens :: [a -> a] -> ArbGen a -unaryGens = mconcat . map unaryGen - -binaryGen :: (a -> a -> a) -> ArbGen a -binaryGen f = pureGen 2 (\xs -> f (head xs) (xs !! 1)) - -binaryGens :: [a -> a -> a] -> ArbGen a -binaryGens = mconcat . map binaryGen - -pureGen :: Int -> ([a] -> a) -> ArbGen a -pureGen n = newGen n . return - -toArbGen :: Gen a -> ArbGen a -toArbGen = newGen 0 . liftM const - -newGen :: Int -> Gen ([a] -> a) -> ArbGen a -newGen n f = AG [(1, (n, f))] - ---------------------------------------------------------- --- Frequency combinators - -common, uncommon, rare :: ArbGen a -> ArbGen a -common = changeFrequency 2 -uncommon = changeFrequency (1/2) -rare = changeFrequency (1/5) - -changeFrequency :: Rational -> ArbGen a -> ArbGen a -changeFrequency r (AG xs) = AG (map (first (*r)) xs)
− src/Ideas/Common/Utils/StringRef.hs
@@ -1,136 +0,0 @@-{-# LANGUAGE DeriveDataTypeable #-} ------------------------------------------------------------------------------ --- Copyright 2016, Ideas project team. This file is distributed under the --- terms of the Apache License 2.0. For more information, see the files --- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution. ------------------------------------------------------------------------------ --- | --- Maintainer : bastiaan.heeren@ou.nl --- Stability : provisional --- Portability : portable (depends on ghc) --- --- References to Strings, proving a fast comparison implementation (Eq and --- Ord) that uses a hash function. Code is based on Daan Leijen's Lazy --- Virutal Machine (LVM) identifiers. --- ------------------------------------------------------------------------------ - -module Ideas.Common.Utils.StringRef - ( StringRef, stringRef, toString, tableStatus - ) where - -import Data.Bits -import Data.Data -import Data.IORef -import Data.List -import System.IO.Unsafe -import qualified Data.IntMap as IM - ----------------------------------------------------------------- --- StringRef datatype and instance declarations - -data StringRef = S !Int - deriving (Eq, Ord, Data, Typeable) - ----------------------------------------------------------------- --- Hash table - -type HashTable = IM.IntMap [String] - -{-# NOINLINE tableRef #-} -tableRef :: IORef HashTable -tableRef = unsafePerformIO (newIORef IM.empty) - ----------------------------------------------------------------- --- Conversion to and from strings - -stringRef :: String -> StringRef -stringRef s = unsafePerformIO $ do - let hash = hashString s - m <- readIORef tableRef - case IM.insertLookupWithKey (const combine) hash [s] m of - (Nothing, new) -> do - writeIORef tableRef new - return (S (encodeIndexZero hash)) - (Just old, new) -> - case elemIndex s old of - Just index -> - return (S (encode hash index)) - Nothing -> do - let index = length old - writeIORef tableRef new - return (S (encode hash index)) - -toString :: StringRef -> String -toString (S i) = unsafePerformIO $ do - m <- readIORef tableRef - case IM.lookup (extractHash i) m of - Just xs -> return (atIndex (extractIndex i) xs) - Nothing -> intErr "id not found" - ----------------------------------------------------------------- --- Bit encoding - -encode :: Int -> Int -> Int -encode hash index = hash + index `shiftL` 12 - -encodeIndexZero :: Int -> Int -encodeIndexZero hash = hash - -extractHash :: Int -> Int -extractHash i = i `mod` 4096 - -extractIndex :: Int -> Int -extractIndex i = i `shiftR` 12 - ----------------------------------------------------------------- --- Hash function - --- simple hash function that performs quite good in practice -hashString :: String -> Int -hashString s = (f s `mod` prime) `mod` maxHash - where - f = foldl' next 0 -- ' strict fold - next n c = n*65599 + fromEnum c - prime = 32537 --65599 -- require: prime < maxHash - -maxHash :: Int -maxHash = 0xFFF -- 12 bits - ----------------------------------------------------------------- --- Utility functions - -atIndex :: Int -> [a] -> a -atIndex 0 (x:_) = x -atIndex i (_:xs) = atIndex (i-1) xs -atIndex _ _ = intErr "corrupt symbol table" - -combine :: Eq a => [a] -> [a] -> [a] -combine [a] = rec - where - rec [] = [a] - rec this@(x:xs) - | a == x = this - | otherwise = x:rec xs -combine _ = intErr "combine" - -intErr :: String -> a -intErr s = error ("Internal error in Ideas.Common.StringRef: " ++ s) - ----------------------------------------------------------------- --- Testing and debugging - -tableStatus :: IO String -tableStatus = readIORef tableRef >>= \m -> - let xs = map f (IM.assocs m) - f (i, ys) = '#' : show i ++ ": " ++ intercalate ", " (map g (frequency ys)) ++ - " [total = " ++ show (length ys) ++ "]" - g (a, n) | n == 1 = show a - | otherwise = show a ++ " (" ++ show n ++ ")" - in return $ unlines xs - -frequency :: Eq a => [a] -> [(a, Int)] -frequency [] = [] -frequency (x:xs) = - let (ys, zs) = partition (==x) xs - in (x, 1+length ys) : frequency zs
− src/Ideas/Common/Utils/TestSuite.hs
@@ -1,420 +0,0 @@------------------------------------------------------------------------------ --- Copyright 2016, Ideas project team. This file is distributed under the --- terms of the Apache License 2.0. For more information, see the files --- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution. ------------------------------------------------------------------------------ --- | --- Maintainer : bastiaan.heeren@ou.nl --- Stability : provisional --- Portability : portable (depends on ghc) --- --- A lightweight wrapper for organizing tests (including QuickCheck tests). It --- introduces the notion of a test suite, and it stores the test results for --- later inspection (e.g., for the generation of a test report). A TestSuite --- is a monoid. --- ------------------------------------------------------------------------------ - -module Ideas.Common.Utils.TestSuite - ( -- * TestSuite - TestSuite, module Data.Monoid - , suite, useProperty, usePropertyWith - , assertTrue, assertNull, assertEquals, assertIO - , assertMessage, assertMessageIO - , onlyWarnings, rateOnError - -- * Running a test suite - , runTestSuite, runTestSuiteResult - -- * Test Suite Result - , Result, subResults, findSubResult - , justOneSuite, allMessages, topMessages - , nrOfTests, nrOfErrors, nrOfWarnings - , timeInterval, makeSummary, printSummary - -- * Message - , Message, message, warning, messageLines - -- * Status - , Status, HasStatus(..) - , isError, isWarning, isOk - -- * Rating - , Rating, HasRating(..) - ) where - -import Control.Exception -import Control.Monad -import Data.Foldable (toList) -import Data.IORef -import Data.List -import Data.Maybe -import Data.Monoid -import Data.Time -import System.IO -import Test.QuickCheck hiding (Result) -import qualified Data.Sequence as S - ----------------------------------------------------------------- --- Test Suite - -newtype TestSuite = TS (S.Seq Test) - -data Test = Case String (IO Message) - | Suite String TestSuite - -instance Monoid TestSuite where - mempty = TS mempty - TS xs `mappend` TS ys = TS (xs <> ys) - -tests :: TestSuite -> [Test] -tests (TS xs) = toList xs - -makeTestSuite :: Test -> TestSuite -makeTestSuite = TS . S.singleton - ----------------------------------------------------------------- --- Test suite constructors - --- | Construct a (named) test suite containing test cases and other suites -suite :: String -> [TestSuite] -> TestSuite -suite s = makeTestSuite . Suite s . mconcat - --- | Turn a QuickCheck property into the test suite. The first argument is --- a label for the property -useProperty :: Testable prop => String -> prop -> TestSuite -useProperty = flip usePropertyWith stdArgs - --- | Turn a QuickCheck property into the test suite, also providing a test --- configuration (Args) -usePropertyWith :: Testable prop => String -> Args -> prop -> TestSuite -usePropertyWith s args = - makeTestSuite . Case s . liftM make . quickCheckWithResult args {chatty=False} - where - make qc = - case qc of - Success {} -> - mempty - Failure {reason = msg} -> - message msg - NoExpectedFailure {} -> - message "no expected failure" - GaveUp {numTests = i} -> - warning ("passed only " ++ show i ++ " tests") - InsufficientCoverage {numTests = i} -> - warning ("only performed " ++ show i ++ " tests") - -assertTrue :: String -> Bool -> TestSuite -assertTrue s = assertIO s . return - -assertNull :: Show a => String -> [a] -> TestSuite -assertNull s xs = assertMessages s (null xs) (map show xs) - -assertEquals :: (Eq a, Show a) => String -> a -> a -> TestSuite -assertEquals s x y = assertMessage s (x==y) $ - "not equal " ++ show x ++ " and " ++ show y - -assertMessage :: String -> Bool -> String -> TestSuite -assertMessage s b = assertMessages s b . return - -assertMessages :: String -> Bool -> [String] -> TestSuite -assertMessages s b xs = makeTestSuite . Case s $ return $ - if b then mempty else mconcat (map message xs) - -assertIO :: String -> IO Bool -> TestSuite -assertIO s = makeTestSuite . Case s . liftM f - where - f b = if b then mempty else message "assertion failed" - -assertMessageIO :: String -> IO Message -> TestSuite -assertMessageIO s = makeTestSuite . Case s - --- | All errors are turned into warnings -onlyWarnings :: TestSuite -> TestSuite -onlyWarnings = changeMessages $ \m -> - m { messageStatus = messageStatus m `min` Warning - , messageRating = mempty - } - -rateOnError :: Int -> TestSuite -> TestSuite -rateOnError n = changeMessages $ \m -> - if isError m then m { messageRating = Rating n } else m - -changeMessages :: (Message -> Message) -> TestSuite -> TestSuite -changeMessages f = changeTS - where - changeTS (TS xs) = TS (fmap changeTest xs) - changeTest (Case s io) = Case s (liftM f io) - changeTest (Suite s t) = Suite s (changeTS t) - ----------------------------------------------------------------- --- Running a test suite - -runTestSuite :: Bool -> TestSuite -> IO () -runTestSuite chattyIO = void . runTestSuiteResult chattyIO - -runTestSuiteResult :: Bool -> TestSuite -> IO Result -runTestSuiteResult chattyIO ts = do - hSetBuffering stdout NoBuffering - ref <- newIORef 0 - result <- runner ref chattyIO ts - newline ref - return result - -runner :: IORef Int -> Bool -> TestSuite -> IO Result -runner ref chattyIO = runTS - where - runTS :: TestSuite -> IO Result - runTS ts = do - (res, dt) <- getDiffTime (foldM addTest mempty (tests ts)) - returnStrict res { diffTime = dt } - - runTest :: Test -> IO Result - runTest t = - case t of - Suite s xs -> runSuite s xs - Case s io -> runTestCase s io - - runSuite ::String -> TestSuite -> IO Result - runSuite s ts = do - when chattyIO $ do - newline ref - putStrLn s - reset ref - result <- runTS ts - returnStrict (suiteResult s result) - - runTestCase :: String -> IO Message -> IO Result - runTestCase s io = do - msg <- io `catch` handler - case messageStatus msg of - _ | not chattyIO -> return () - Ok -> dot ref - _ -> do - newlineIndent ref - print msg - reset ref - returnStrict (caseResult (s, msg)) - where - handler :: SomeException -> IO Message - handler = return . message . show - - addTest :: Result -> Test -> IO Result - addTest res t = liftM (res <>) (runTest t) - --- formatting helpers -type WriteIO a = IORef Int -> IO a - -newline :: WriteIO () -newline ref = do - i <- readIORef ref - when (i>0) (putChar '\n') - reset ref - -newlineIndent :: WriteIO () -newlineIndent ref = do - newline ref - putStr " " - writeIORef ref 3 - -dot :: WriteIO () -dot ref = do - i <- readIORef ref - unless (i>0 && i<60) (newlineIndent ref) - putChar '.' - modifyIORef ref (+1) - -reset :: WriteIO () -reset = (`writeIORef` 0) - ----------------------------------------------------------------- --- Test Suite Result - -data Result = Result - { suites :: S.Seq (String, Result) - , cases :: S.Seq (String, Message) - , diffTime :: !NominalDiffTime - , nrOfTests :: !Int - , nrOfWarnings :: !Int - , nrOfErrors :: !Int - , resultRating :: !Rating - } - --- one-line summary -instance Show Result where - show result = - "(tests: " ++ show (nrOfTests result) ++ - ", errors: " ++ show (nrOfErrors result) ++ - ", warnings: " ++ show (nrOfWarnings result) ++ - ", " ++ show (diffTime result) ++ ")" - -instance Monoid Result where - mempty = Result mempty mempty 0 0 0 0 mempty - x `mappend` y = Result - { suites = suites x <> suites y - , cases = cases x <> cases y - , diffTime = diffTime x + diffTime y - , nrOfTests = nrOfTests x + nrOfTests y - , nrOfWarnings = nrOfWarnings x + nrOfWarnings y - , nrOfErrors = nrOfErrors x + nrOfErrors y - , resultRating = resultRating x <> resultRating y - } - -instance HasStatus Result where - getStatus r | nrOfErrors r > 0 = Error - | nrOfWarnings r > 0 = Warning - | otherwise = Ok - -instance HasRating Result where - rating = rating . resultRating - rate n a = a {resultRating = Rating n} - -suiteResult :: String -> Result -> Result -suiteResult s res = mempty - { suites = S.singleton (s, res) - , nrOfTests = nrOfTests res - , nrOfWarnings = nrOfWarnings res - , nrOfErrors = nrOfErrors res - , resultRating = resultRating res - } - -caseResult :: (String, Message) -> Result -caseResult x@(_, msg) = - case getStatus msg of - Ok -> new - Warning -> new { nrOfWarnings = 1 } - Error -> new { nrOfErrors = 1 } - where - new = mempty - { cases = S.singleton x - , nrOfTests = 1 - , resultRating = messageRating msg - } - -subResults :: Result -> [(String, Result)] -subResults = toList . suites - -topMessages :: Result -> [(String, Message)] -topMessages = toList . cases - -allMessages :: Result -> [(String, Message)] -allMessages res = - topMessages res ++ concatMap (allMessages . snd) (subResults res) - -findSubResult :: String -> Result -> Maybe Result -findSubResult name = listToMaybe . recs - where - recs = concatMap rec . subResults - rec (n, t) - | n == name = [t] - | otherwise = recs t - -justOneSuite :: Result -> Maybe (String, Result) -justOneSuite res = - case subResults res of - [x] | S.null (cases res) -> Just x - _ -> Nothing - -timeInterval :: Result -> Double -timeInterval = fromRational . toRational . diffTime - -printSummary :: Result -> IO () -printSummary = putStrLn . makeSummary - -makeSummary :: Result -> String -makeSummary result = unlines $ - [ line - , "Tests : " ++ show (nrOfTests result) - , "Errors : " ++ show (nrOfErrors result) - , "Warnings : " ++ show (nrOfWarnings result) - , "" - , "Time : " ++ show (diffTime result) - , "" - , "Suites: " - ] ++ map f (subResults result) - ++ [line] - where - line = replicate 75 '-' - f (name, r) = " " ++ name ++ " " ++ show r - ------------------------------------------------------ --- Message - -data Message = M - { messageStatus :: !Status - , messageRating :: !Rating - , messageLines :: [String] - } - deriving Eq - -instance Show Message where - show a = st ++ sep ++ msg - where - msg = intercalate ", " (messageLines a) - sep = if null st || null msg then "" else ": " - st | isError a = "error" - | isWarning a = "warning" - | null (messageLines a) = "ok" - | otherwise = "" - -instance Monoid Message where - mempty = M mempty mempty mempty - M s r xs `mappend` M t q ys = M (s <> t) (r <> q) (xs <> ys) - -instance HasStatus Message where - getStatus = messageStatus - -instance HasRating Message where - rating = rating . messageRating - rate n a = a {messageRating = Rating n} - -message :: String -> Message -message = M Error (Rating 0) . return - -warning :: String -> Message -warning = M Warning mempty . return - ------------------------------------------------------ --- Status - -data Status = Ok | Warning | Error - deriving (Eq, Ord) - -instance Monoid Status where - mempty = Ok - mappend = max - -class HasStatus a where - getStatus :: a -> Status - -isOk, isWarning, isError :: HasStatus a => a -> Bool -isOk = (== Ok) . getStatus -isWarning = (== Warning) . getStatus -isError = (== Error) . getStatus - ------------------------------------------------------ --- Rating - -data Rating = Rating !Int | MaxRating - deriving (Eq, Ord) - -instance Monoid Rating where - mempty = MaxRating - mappend = min - -class HasRating a where - rating :: a -> Maybe Int - rate :: Int -> a -> a - -instance HasRating Rating where - rating (Rating n) = Just n - rating MaxRating = Nothing - rate = const . Rating - ------------------------------------------------------ --- Utility function - -getDiffTime :: IO a -> IO (a, NominalDiffTime) -getDiffTime action = do - t0 <- getCurrentTime - a <- action - t1 <- getCurrentTime - return (a, diffUTCTime t1 t0) - -returnStrict :: Monad m => a -> m a -returnStrict a = a `seq` return a
− src/Ideas/Common/Utils/Uniplate.hs
@@ -1,25 +0,0 @@------------------------------------------------------------------------------ --- Copyright 2016, Ideas project team. This file is distributed under the --- terms of the Apache License 2.0. For more information, see the files --- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution. ------------------------------------------------------------------------------ --- | --- Maintainer : bastiaan.heeren@ou.nl --- Stability : provisional --- Portability : portable (depends on ghc) --- --- Exports a subset of Data.Generics.Uniplate.Direct (the @Uniplate@ type --- class and its utility plus constructor functions) --- ------------------------------------------------------------------------------ - -module Ideas.Common.Utils.Uniplate - ( -- * Uniplate type class and utility functions - Uniplate - , children, contexts, descend, descendM, holes, para - , rewrite, rewriteM, transform, transformM, uniplate, universe - -- * Instance constructors - , (|-), (|*), (||*), plate - ) where - -import Data.Generics.Uniplate.Direct
src/Ideas/Common/View.hs view
@@ -39,7 +39,6 @@ ) where import Control.Arrow -import Control.Monad import Data.Maybe import Ideas.Common.Classes import Ideas.Common.Id @@ -101,7 +100,7 @@ canonicalWithM :: IsView f => (b -> Maybe b) -> f a b -> a -> Maybe a canonicalWithM f view a = - match view a >>= liftM (build view) . f + match view a >>= fmap (build view) . f isCanonical :: (IsView f, Eq a) => f a b -> a -> Bool isCanonical = isCanonicalWith (==)
src/Ideas/Encoding/DecoderJSON.hs view
@@ -40,14 +40,14 @@ decodeType tp = case tp of Tag _ t -> decodeType t - Iso p t -> liftM (from p) (decodeType t) + Iso p t -> from p <$> decodeType t Pair t1 t2 -> do a <- decodeType t1 b <- decodeType t2 return (a, b) t1 :|: t2 -> - liftM Left (decodeType t1) `mplus` - liftM Right (decodeType t2) + (Left <$> decodeType t1) `mplus` + (Right <$> decodeType t2) Unit -> return () Const QCGen -> getQCGen Const Script -> getScript @@ -86,7 +86,7 @@ decodeLocation :: JSONDecoder a Location decodeLocation = decoderFor $ \json -> case json of - String s -> liftM toLocation (readM s) + String s -> toLocation <$> readM s _ -> fail "expecting a string for a location" decodeState :: JSONDecoder a (State a) @@ -126,7 +126,7 @@ case json of String p | p ~= "noprefix" -> return (\_ _ -> noPrefix) - | otherwise -> liftM replayPaths (readPaths p) + | otherwise -> replayPaths <$> readPaths p _ -> fail "invalid prefixes" where x ~= y = filter isAlphaNum (map toLower x) == y @@ -145,14 +145,15 @@ decodeContext :: JSONDecoder a (Context a) decodeContext = do ex <- getExercise - liftM (inContext ex) decodeExpression + inContext ex <$> decodeExpression decodeExpression :: JSONDecoder a a decodeExpression = withJSONTerm $ \b -> getExercise >>= decoderFor . f b where f True ex json = - let Just v = hasTermView ex - in matchM v (jsonToTerm json) + case hasJSONView ex of + Just v -> matchM v json + Nothing -> fail "JSON encoding not supported by exercise" f False ex json = case json of String s -> either fail return (parser ex s)
src/Ideas/Encoding/DecoderXML.hs view
@@ -23,7 +23,7 @@ import Ideas.Common.Traversal.Navigator import Ideas.Encoding.Encoder import Ideas.Encoding.OpenMathSupport -import Ideas.Service.Request +import Ideas.Encoding.Request import Ideas.Service.State import Ideas.Service.Types import Ideas.Text.OpenMath.Object @@ -43,14 +43,14 @@ maybe (fail "unknown difficulty level") (return . g) (readDifficulty a) | otherwise -> decodeChild s (xmlDecoder t) - Iso p t -> liftM (from p) (xmlDecoder t) + Iso p t -> from p <$> xmlDecoder t Pair t1 t2 -> do x <- xmlDecoder t1 y <- xmlDecoder t2 return (x, y) t1 :|: t2 -> - liftM Left (xmlDecoder t1) `mplus` - liftM Right (xmlDecoder t2) + (Left <$> xmlDecoder t1) `mplus` + (Right <$> xmlDecoder t2) Unit -> return () Const ctp -> case ctp of @@ -112,7 +112,7 @@ locRef = makeRef "location" case locRef ? env of Just s -> maybe (fail "invalid location") return $ do - loc <- liftM toLocation (readM s) + loc <- toLocation <$> readM s navigateTo loc (deleteRef locRef ctx) Nothing -> return ctx @@ -159,8 +159,7 @@ decodeConfiguration :: XMLDecoder a StrategyCfg decodeConfiguration = decodeChild "configuration" $ decoderFor $ \xml -> - liftM mconcat $ - mapM decodeAction (children xml) + mconcat <$> mapM decodeAction (children xml) where decodeAction item = do guard (null (children item)) @@ -170,7 +169,7 @@ decodeArgEnvironment :: XMLDecoder a Environment decodeArgEnvironment = decoderFor $ - liftM makeEnvironment . mapM (decodeBinding //) . findChildren "argument" + fmap makeEnvironment . mapM (decodeBinding //) . findChildren "argument" decodeBinding :: XMLDecoder a Binding decodeBinding = decoderFor $ \xml -> do
src/Ideas/Encoding/Encoder.hs view
@@ -14,12 +14,14 @@ module Ideas.Encoding.Encoder ( -- * Converter type class Converter(..) - , getExercise, getQCGen, getScript, getRequest + , getExercise, getBaseUrl, getQCGen, getScript, getRequest , withExercise, withOpenMath, withJSONTerm, (//) - -- * JSON terms - , termToJSON, jsonToTerm, jsonTermView - -- * Options - , Options, simpleOptions, makeOptions + -- * JSON support + , hasJSONView, addJSONView, jsonEncoding + , termToJSON, jsonToTerm + -- * Latex support + , hasLatexEncoding, latexPrinter, latexPrinterContext + , latexEncoding, latexEncodingWith -- * Encoder datatype , Encoder, TypedEncoder , makeEncoder, encoderFor, exerciseEncoder @@ -35,14 +37,15 @@ import Control.Applicative as Export hiding (Const) import Control.Arrow as Export import Control.Monad +import Data.Maybe import Data.Monoid as Export import Ideas.Common.Library hiding (exerciseId, symbol) -import Ideas.Common.Utils (Some(..)) -import Ideas.Service.DomainReasoner -import Ideas.Service.FeedbackScript.Parser (parseScriptSafe, Script) -import Ideas.Service.Request +import Ideas.Encoding.Options +import Ideas.Encoding.Request +import Ideas.Service.FeedbackScript.Parser (Script) import Ideas.Service.Types import Ideas.Text.JSON hiding (String) +import Ideas.Text.Latex import Ideas.Text.XML import Test.QuickCheck.Random import qualified Control.Category as C @@ -53,14 +56,18 @@ -- Converter type class class Converter f where - fromOptions :: (Options a -> t) -> f a s t - run :: Monad m => f a s t -> Options a -> s -> m t + fromExercise :: (Exercise a -> t) -> f a s t + fromOptions :: (Options -> t) -> f a s t + run :: Monad m => f a s t -> Exercise a -> Options -> s -> m t getExercise :: Converter f => f a s (Exercise a) -getExercise = fromOptions exercise +getExercise = fromExercise id +getBaseUrl :: Converter f => f a s String +getBaseUrl = fromOptions (fromMaybe "http://ideas.cs.uu.nl/" . baseUrl) + getQCGen :: Converter f => f a s QCGen -getQCGen = fromOptions qcGen +getQCGen = fromOptions (fromMaybe (mkQCGen 0) . qcGen) getScript :: Converter f => f a s Script getScript = fromOptions script @@ -72,19 +79,32 @@ withExercise = (getExercise >>=) withOpenMath :: (Converter f, Monad (f a s)) => (Bool -> f a s t) -> f a s t -withOpenMath = (liftM useOpenMath getRequest >>=) +withOpenMath = (fmap useOpenMath getRequest >>=) withJSONTerm :: (Converter f, Monad (f a s)) => (Bool -> f a s t) -> f a s t -withJSONTerm = (liftM useJSONTerm getRequest >>=) +withJSONTerm = (fmap useJSONTerm getRequest >>=) (//) :: (Converter f, Monad (f a s2)) => f a s t -> s -> f a s2 t p // a = do - xs <- fromOptions id - run p xs a + opts <- fromOptions id + ex <- getExercise + run p ex opts a ------------------------------------------------------------------- -- JSON terms +jsonProperty :: Id +jsonProperty = describe "Support for JSON encoding" $ newId "json" + +hasJSONView :: Exercise a -> Maybe (View JSON a) +hasJSONView = getPropertyF jsonProperty + +addJSONView :: View JSON a -> Exercise a -> Exercise a +addJSONView = setPropertyF jsonProperty + +jsonEncoding :: InJSON a => Exercise a -> Exercise a +jsonEncoding = addJSONView (makeView fromJSON toJSON) + termToJSON :: Term -> JSON termToJSON term = case term of @@ -120,55 +140,44 @@ where f (s, x) = [TVar s, jsonToTerm x] -jsonTermView :: InJSON a => View Term a -jsonTermView = makeView (fromJSON . termToJSON) (jsonToTerm . toJSON) - -trueSymbol, falseSymbol, nullSymbol, objectSymbol :: Symbol -trueSymbol = newSymbol "true" -falseSymbol = newSymbol "false" +nullSymbol, objectSymbol :: Symbol nullSymbol = newSymbol "null" objectSymbol = newSymbol "object" ------------------------------------------------------------------- --- Options +-- Latex support -data Options a = Options - { exercise :: Exercise a -- the current exercise - , request :: Request -- meta-information about the request - , qcGen :: QCGen -- random number generator - , script :: Script -- feedback script - } +latexProperty :: Id +latexProperty = describe "Support for LaTeX encoding" $ newId "latex" -simpleOptions :: Exercise a -> Options a -simpleOptions ex = - let req = emptyRequest {encoding = [EncHTML]} - gen = mkQCGen 0 - in Options ex req gen mempty +newtype F a = F { unF :: a -> Latex } -makeOptions :: DomainReasoner -> Request -> IO (Some Options) -makeOptions dr req = do - Some ex <- - case exerciseId req of - Just code -> findExercise dr code - Nothing -> return (Some emptyExercise) +getF :: Exercise a -> Maybe (F a) +getF = getPropertyF latexProperty - scr <- case feedbackScript req of - Just s -> parseScriptSafe s - Nothing - | getId ex == mempty -> return mempty - | otherwise -> defaultScript dr (getId ex) - gen <- maybe newQCGen (return . mkQCGen) (randomSeed req) - return $ Some Options - { exercise = ex - , request = req - , qcGen = gen - , script = scr - } +hasLatexEncoding :: Exercise a -> Bool +hasLatexEncoding = isJust . getF +-- | Uses exercise pretty-printer in case latex encoding is missing. +latexPrinter :: Exercise a -> a -> Latex +latexPrinter ex = maybe (toLatex . prettyPrinter ex) unF (getF ex) + +-- | Uses exercise pretty-printer in case latex encoding is missing. +latexPrinterContext :: Exercise a -> Context a -> Latex +latexPrinterContext ex ctx = + let def = toLatex (prettyPrinterContext ex ctx) + in fromMaybe def (unF <$> getF ex <*> fromContext ctx) + +latexEncoding :: ToLatex a => Exercise a -> Exercise a +latexEncoding = latexEncodingWith toLatex + +latexEncodingWith :: (a -> Latex) -> Exercise a -> Exercise a +latexEncodingWith = setPropertyF latexProperty . F + ------------------------------------------------------------------- -- Encoder datatype -newtype Encoder a s t = Enc { runEnc :: Options a -> s -> Error t } +newtype Encoder a s t = Enc { runEnc :: (Exercise a, Options) -> s -> Error t } type TypedEncoder a = Encoder a (TypedValue (Type a)) @@ -180,32 +189,35 @@ arr f = Enc $ \_ -> return . f first f = Enc $ \xs (a, b) -> runEnc f xs a >>= \c -> return (c, b) +instance Functor (Encoder a s) where + fmap f p = Enc $ \xs s -> f <$> runEnc p xs s + +instance Applicative (Encoder a s) where + pure a = Enc $ \_ _ -> return a + p <*> q = Enc $ \xs s -> do + f <- runEnc p xs s + f <$> runEnc q xs s + instance Alternative (Encoder a s) where - empty = mzero - (<|>) = mplus + empty = fail "Encoder: emptu" + p <|> q = Enc $ \xs s -> + runEnc p xs s <|> runEnc q xs s instance Monad (Encoder a s) where - return a = Enc $ \_ _ -> return a + return = pure fail s = Enc $ \_ _ -> fail s p >>= f = Enc $ \xs s -> do a <- runEnc p xs s runEnc (f a) xs s instance MonadPlus (Encoder a s) where - mzero = fail "Decoder: mzero" - mplus p q = Enc $ \xs s -> - runEnc p xs s `mplus` runEnc q xs s - -instance Functor (Encoder a s) where - fmap = liftM - -instance Applicative (Encoder a s) where - pure = return - (<*>) = liftM2 ($) + mzero = fail "Encoder: mzero" + mplus = (<|>) instance Converter Encoder where - fromOptions f = Enc $ \xs _ -> return (f xs) - run f xs = runErrorM . runEnc f xs + fromExercise f = Enc $ \(ex, _) _ -> return (f ex) + fromOptions f = Enc $ \(_, opts) _ -> return (f opts) + run f ex opts = runErrorM . runEnc f (ex, opts) instance Monoid t => Monoid (Encoder a s t) where mempty = pure mempty @@ -215,7 +227,7 @@ n .=. s = pure (n .=. s) unescaped = pure . unescaped builder = pure . builder - tag = liftA . tag + tag = fmap . tag makeEncoder :: (s -> t) -> Encoder a s t makeEncoder = arr @@ -242,12 +254,25 @@ ------------------------------------------------------------------- -- Decoder datatype -newtype Decoder a s t = Dec { runDec :: Options a -> s -> Error (t, s) } +newtype Decoder a s t = Dec { runDec :: (Exercise a, Options) -> s -> Error (t, s) } type TypedDecoder a s = forall t . Type a t -> Decoder a s t +instance Functor (Decoder a s) where + fmap f p = Dec $ \xs s -> mapFirst f <$> runDec p xs s + +instance Applicative (Decoder a s) where + pure a = Dec $ \_ s -> return (a, s) + p <*> q = Dec $ \xs s1 -> do + (f, s2) <- runDec p xs s1 + mapFirst f <$> runDec q xs s2 + +instance Alternative (Decoder a s) where + empty = fail "Decoder: empty" + p <|> q = Dec $ \xs s -> runDec p xs s <|> runDec q xs s + instance Monad (Decoder a s) where - return a = Dec $ \_ s -> return (a, s) + return = pure fail s = Dec $ \_ _ -> fail s p >>= f = Dec $ \xs s1 -> do (a, s2) <- runDec p xs s1 @@ -255,19 +280,7 @@ instance MonadPlus (Decoder a s) where mzero = fail "Decoder: mzero" - mplus p q = Dec $ \xs s -> - runDec p xs s `mplus` runDec q xs s - -instance Functor (Decoder a s) where - fmap = liftM - -instance Applicative (Decoder a s) where - pure = return - (<*>) = liftM2 ($) - -instance Alternative (Decoder a s) where - empty = fail "Decoder: empty" - (<|>) = mplus + mplus = (<|>) get :: Decoder a s s get = Dec $ \_ s -> return (s, s) @@ -276,8 +289,9 @@ put s = Dec $ \_ _ -> return ((), s) instance Converter Decoder where - fromOptions f = Dec $ \xs s -> return (f xs, s) - run f xs = liftM fst . runErrorM . runDec f xs + fromExercise f = Dec $ \(ex, _) s -> return (f ex, s) + fromOptions f = Dec $ \(_, opts) s -> return (f opts, s) + run f ex opts = fmap fst . runErrorM . runDec f (ex, opts) split :: (s -> Either String (t, s)) -> Decoder a s t split f = get >>= either fail (\(a, s2) -> put s2 >> return a) . f @@ -303,28 +317,32 @@ newtype Error a = Error { runError :: Either String a } instance Functor Error where - fmap = (<$>) + fmap f = Error . fmap f . runError instance Applicative Error where - pure = return - (<*>) = ap + pure = Error . Right + p <*> q = Error $ + case (runError p, runError q) of + (Left s, _) -> Left s + (_, Left s) -> Left s + (Right f, Right x) -> Right (f x) instance Alternative Error where - empty = mzero - (<|>) = mplus + empty = Error (Left "empty") + p <|> q = Error $ + case (runError p, runError q) of + (Right a, _) -> Right a + (_, Right a) -> Right a + (Left s, _) -> Left s instance Monad Error where fail = Error . Left - return = Error . Right + return = pure m >>= f = Error $ either Left (runError . f) (runError m) instance MonadPlus Error where - mzero = fail "mzero" - mplus p q = Error $ - case (runError p, runError q) of - (Right a, _) -> Right a - (_, Right a) -> Right a - (Left s, _) -> Left s + mzero = fail "mzero" + mplus = (<|>) runErrorM :: Monad m => Error a -> m a runErrorM = either fail return . runError
src/Ideas/Encoding/EncoderHTML.hs view
@@ -13,7 +13,7 @@ -- ----------------------------------------------------------------------------- -module Ideas.Encoding.EncoderHTML (htmlEncoder, htmlEncoderAt) where +module Ideas.Encoding.EncoderHTML (htmlEncoder) where import Data.Char import Data.List @@ -21,40 +21,38 @@ import Data.Ord import Ideas.Common.Library hiding (alternatives) import Ideas.Common.Strategy.Symbol -import Ideas.Common.Utils -import Ideas.Common.Utils.TestSuite import Ideas.Encoding.Encoder import Ideas.Encoding.LinkManager +import Ideas.Encoding.Request import Ideas.Encoding.RulePresenter import Ideas.Encoding.RulesInfo import Ideas.Encoding.StrategyInfo import Ideas.Service.BasicServices import Ideas.Service.Diagnose import Ideas.Service.DomainReasoner -import Ideas.Service.Request import Ideas.Service.State import Ideas.Service.Types import Ideas.Text.HTML import Ideas.Text.OpenMath.FMP import Ideas.Text.OpenMath.Object import Ideas.Text.XML +import Ideas.Utils.TestSuite import System.IO.Unsafe type HTMLEncoder a t = Encoder a t HTMLBuilder htmlEncoder :: DomainReasoner -> TypedEncoder a HTMLPage -htmlEncoder = htmlEncoderAt 0 - -htmlEncoderAt :: Int -> DomainReasoner -> TypedEncoder a HTMLPage -htmlEncoderAt n dr = do - req <- getRequest - let lm = f (maybe staticLinks dynamicLinks (cgiBinary req)) - f = if n==0 then id else linksUp n - makePage lm dr <$> encodeType lm dr +htmlEncoder dr = do + req <- getRequest + base <- getBaseUrl + let lm = makeLinkManager base (fromMaybe "" (cgiBinary req)) + ex <- getExercise + makePage lm dr ex <$> encodeType lm dr -makePage :: LinkManager -> DomainReasoner -> HTMLBuilder -> HTMLPage -makePage lm dr a = +makePage :: LinkManager -> DomainReasoner -> Exercise a -> HTMLBuilder -> HTMLPage +makePage lm dr ex a = addCSS (urlForCSS lm "ideas.css") $ + (if hasLatexEncoding ex then addScript mathJaxUrl else id) $ htmlPage "Ideas: documentation pages" $ mconcat [ divClass "page-header" $ mconcat [ divClass "ideas-logo" space @@ -67,6 +65,9 @@ , divClass "page-footer" $ string (fullVersion dr) ] + where + mathJaxUrl = + "https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-MML-AM_CHTML" encodeType :: LinkManager -> DomainReasoner -> HTMLEncoder a (TypedValue (Type a)) encodeType lm dr = @@ -234,9 +235,7 @@ ] | isJust (randomExercise ex) ] ++ - [ para $ submitStateInfo lm ex - | not (isStatic lm) - ] + [ para $ submitStateInfo lm ex ] ] where generalInfo ex = keyValueTable @@ -416,15 +415,14 @@ encodeExampleList lm = exerciseEncoder $ \ex pairs -> mconcat $ h2 "Examples" : [ h3 (s ++ " (" ++ show (length xs) ++ ")") - <> (if isStatic lm then ul else mconcat) (map (make ex) xs) + <> mconcat (map (make ex) xs) | (_, s, xs) <- orderedGroupsWith show fst pairs ] where make ex (_, x) = para $ - munless (isStatic lm) ( - let st = emptyStateContext ex x - in spanClass "statelink" $ linkToState lm st $ external lm) - <> spanClass "term" (string (prettyPrinterContext ex x)) + ( let st = emptyStateContext ex x + in spanClass "statelink" $ linkToState lm st $ external lm) + <> htmlContext False ex x external :: BuildXML a => LinkManager -> a external lm = element "img" @@ -457,23 +455,30 @@ , showEnv env1 -- local environment , showEnv env2 -- global environment (diff) ] - textLines = mconcat . intersperse br . map string . lines - forTerm a = - divClass "term" $ textLines $ prettyPrinterContext ex a + forTerm = htmlContext True ex in htmlDerivationWith before forStep forTerm (diffEnvironment d) htmlState :: LinkManager -> HTMLEncoder a (State a) htmlState lm = makeEncoder $ \state -> para $ divClass "state" $ stateLink lm state - <> divClass "term" (string $ prettyPrinterContext (exercise state) (stateContext state)) + <> htmlContext True (exercise state) (stateContext state) <> string "ready: " <> bool (finished state) +htmlContext :: Bool -> Exercise a -> Context a -> HTMLBuilder +htmlContext useDiv ex = f "term" . textLines . printer + where + textLines = mconcat . intersperse br . map string . lines + f = if useDiv then divClass else spanClass + + inline s = "\\(" ++ s ++ "\\)" + printer + | hasLatexEncoding ex = inline . show . latexPrinterContext ex + | otherwise = prettyPrinterContext ex + stateLink :: LinkManager -> State a -> HTMLBuilder -stateLink lm st - | isStatic lm = mempty - | otherwise = - spanClass "derivation-statelink" $ linkToState lm st $ external lm +stateLink lm st = + spanClass "derivation-statelink" $ linkToState lm st $ external lm encodeState :: LinkManager -> DomainReasoner -> HTMLEncoder a (State a) encodeState lm dr =
src/Ideas/Encoding/EncoderJSON.hs view
@@ -17,11 +17,11 @@ import Data.Maybe import Ideas.Common.Library hiding (exerciseId) -import Ideas.Common.Utils (Some(..), distinct) import Ideas.Encoding.Encoder hiding (symbol) import Ideas.Service.State import Ideas.Service.Types hiding (String) import Ideas.Text.JSON +import Ideas.Utils.Prelude (distinct) import qualified Ideas.Service.Diagnose as Diagnose import qualified Ideas.Service.Submit as Submit import qualified Ideas.Service.Types as Tp @@ -60,7 +60,7 @@ tupleList (p ::: Tp.Pair t1 t2) = tupleList (fst p ::: t1) ++ tupleList (snd p ::: t2) tupleList (x ::: Tag s t) - | s `elem` ["Message"] = tupleList (x ::: t) + | s == "Message" = tupleList (x ::: t) tupleList (ev ::: (t1 :|: t2)) = either (\x -> tupleList (x ::: t1)) (\x -> tupleList (x ::: t2)) ev @@ -94,12 +94,8 @@ encodeContext :: JSONEncoder a (Context a) encodeContext = withJSONTerm (exerciseEncoder . f) where - f True ex ctx = fromMaybe Null $ do - v <- hasTermView ex - a <- fromContext ctx - return (termToJSON (build v a)) - f False ex ctx = - String $ prettyPrinterContext ex ctx + f True ex = fromMaybe Null . liftA2 build (hasJSONView ex) . fromContext + f False ex = String . prettyPrinterContext ex encodeState :: JSONEncoder a (State a) encodeState = encoderFor $ \st -> @@ -187,7 +183,7 @@ Diagnose.Unknown b st -> make "unknown" [fromReady b, fromState st] where - make s = liftA (\xs -> Object [(s, Array xs)]) . sequence + make s = fmap (\xs -> Object [(s, Array xs)]) . sequence fromEnv env = jsonEncoder // (env ::: tEnvironment) fromRule r = pure (toJSON (showId r)) fromMaybeRule mr = pure (maybe Null (toJSON . showId) mr) @@ -208,11 +204,12 @@ jsonTuple :: [JSON] -> JSON jsonTuple xs = - case mapM f xs of + case catMaybes <$> mapM f xs of Just ys | distinct (map fst ys) -> Object ys _ -> Array xs where - f (Object [p]) = Just p + f (Object [p]) = Just (Just p) + f Null = Just Nothing f _ = Nothing ruleShortInfo :: Rule a -> JSON
src/Ideas/Encoding/EncoderXML.hs view
@@ -21,8 +21,7 @@ import Data.Char import Data.Maybe import Data.Monoid -import Ideas.Common.Library hiding (exerciseId, (:=), alternatives) -import Ideas.Common.Utils (Some(..)) +import Ideas.Common.Library hiding (exerciseId, alternatives) import Ideas.Encoding.Encoder import Ideas.Encoding.OpenMathSupport import Ideas.Encoding.RulesInfo (rulesInfoXML)
src/Ideas/Encoding/Evaluator.hs view
@@ -15,7 +15,8 @@ import Ideas.Common.Library import Ideas.Encoding.Encoder -import Ideas.Main.Logging +import Ideas.Encoding.Logging +import Ideas.Encoding.Options import Ideas.Service.Diagnose import Ideas.Service.Types @@ -36,16 +37,16 @@ [] -> return () hd:_ -> changeLog logRef (f hd) -evalService :: LogRef -> Options a -> Evaluator a b c -> Service -> b -> IO c -evalService logRef opts f srv b = do - res <- eval opts f b (serviceFunction srv) +evalService :: LogRef -> Exercise a -> Options -> Evaluator a b c -> Service -> b -> IO c +evalService logRef ex opts f srv b = do + res <- eval ex opts f b (serviceFunction srv) logType logRef res tState addState logType logRef res tRule $ \rl r -> r {ruleid = showId rl} logType logRef res tDiagnosis $ \d r -> r {serviceinfo = show d} return (evalResult res) -eval :: Options a -> Evaluator a b c -> b -> TypedValue (Type a) -> IO (EvalResult a c) -eval opts (Evaluator dec enc) b = rec +eval :: Exercise a -> Options -> Evaluator a b c -> b -> TypedValue (Type a) -> IO (EvalResult a c) +eval ex opts (Evaluator dec enc) b = rec where rec tv@(val ::: tp) = case tp of @@ -56,7 +57,7 @@ t1 :-> t2 :-> t3 -> rec (uncurry val ::: Pair t1 t2 :-> t3) t1 :-> t2 -> do - a <- run (dec t1) opts b + a <- run (dec t1) ex opts b res <- rec (val a ::: t2) return res { inputValues = (a ::: t1) : inputValues res } -- perform IO @@ -64,5 +65,5 @@ a <- val rec (a ::: t) _ -> do - c <- run enc opts tv + c <- run enc ex opts tv return $ EvalResult [] tv c
src/Ideas/Encoding/LinkManager.hs view
@@ -14,9 +14,9 @@ ----------------------------------------------------------------------------- module Ideas.Encoding.LinkManager - ( LinkManager(..) - , dynamicLinks, stateToXML - , staticLinks, linksUp, pathLevel, (</>) + ( LinkManager(..), makeLinkManager + , stateToXML + -- , pathLevel, (</>) -- links to services and exercises , linkToIndex, linkToExercises, linkToServices, linkToService -- links to exercise information @@ -31,6 +31,7 @@ import Ideas.Common.Library import Ideas.Encoding.Encoder import Ideas.Encoding.EncoderXML +import Ideas.Encoding.Options import Ideas.Service.State import Ideas.Service.Types import Ideas.Text.HTML @@ -40,7 +41,6 @@ { urlForCSS :: String -> String , urlForImage :: String -> String , urlForRequest :: String - , isStatic :: Bool -- links to services and exercises , urlForIndex :: String , urlForExercises :: String @@ -130,12 +130,11 @@ --------------------------------------------------------------------- -- Dynamic links -dynamicLinks :: String -> LinkManager -dynamicLinks cgiBinary = LinkManager - { isStatic = False - , urlForRequest = prefix - , urlForCSS = ("http://ideas.cs.uu.nl/css/" ++) - , urlForImage = ("http://ideas.cs.uu.nl/images/" ++) +makeLinkManager :: String -> String -> LinkManager +makeLinkManager base cgiBinary = LinkManager + { urlForRequest = prefix + , urlForCSS = \s -> base ++ "css/" ++ s + , urlForImage = \s -> base ++ "images/" ++ s , urlForIndex = url $ simpleRequest "index" , urlForExercises = url $ simpleRequest "exerciselist" , urlForServices = url $ simpleRequest "servicelist" @@ -186,7 +185,7 @@ -- assume nothing goest wrong stateToXML :: State a -> XMLBuilder stateToXML st = fromMaybe (error "LinkManager: Invalid state") $ - run encodeState (simpleOptions (exercise st)) st + run encodeState (exercise st) optionHtml st linkWith :: (a -> String) -> a -> HTMLBuilder -> HTMLBuilder linkWith f = link . escapeInURL . f @@ -200,80 +199,4 @@ f '%' = "%25" f '#' = "%23" f ';' = "%3B" - f c = [c] - ---------------------------------------------------------------------- --- Static links - -staticLinks :: LinkManager -staticLinks = LinkManager - { isStatic = True - , urlForCSS = id - , urlForImage = id - , urlForRequest = "" - , -- links to services and exercises - urlForIndex = "index.html" - , urlForExercises = "exercises.html" - , urlForServices = "services.html" - , urlForService = \srv -> "services" </> idToFilePath srv - -- links to exercise information - , urlForExercise = idToFilePath - , urlForStrategy = idToFilePathWith "-strategy.html" - , urlForRules = idToFilePathWith "-rules.html" - , urlForExamples = idToFilePathWith "-examples.html" - , urlForDerivations = idToFilePathWith "-derivations.html" - , urlForRule = \ex r -> idToFilePathWith ("/" ++ showId r ++ ".html") ex - , urlForTestReport = idToFilePathWith "-testreport.html" - -- dynamic exercise information - , urlForRandomExample = \_ _ -> "" - -- dynamic state information - , urlForState = const "" - , urlForFirsts = const "" - , urlForApplications = const "" - , urlForDerivation = const "" - , urlForMicrosteps = const "" - } - -linksUp :: Int -> LinkManager -> LinkManager -linksUp n lm = lm - { isStatic = isStatic lm - -- links to services and exercises - , urlForIndex = f0 urlForIndex - , urlForExercises = f0 urlForExercises - , urlForServices = f0 urlForServices - , urlForService = f1 urlForService - -- links to exercise information - , urlForExercise = f1 urlForExercise - , urlForStrategy = f1 urlForStrategy - , urlForRules = f1 urlForRules - , urlForExamples = f1 urlForExamples - , urlForDerivations = f1 urlForDerivations - , urlForRule = f2 urlForRule - -- dynamic exercise information - , urlForRandomExample = f2 urlForRandomExample - -- dynamic state information - , urlForState = f1 urlForState - , urlForFirsts = f1 urlForFirsts - , urlForApplications = f1 urlForApplications - , urlForDerivation = f1 urlForDerivation - , urlForMicrosteps = f1 urlForMicrosteps - } - where - f0 g = pathUp n $ g lm - f1 g = pathUp n . g lm - f2 g x = pathUp n . g lm x - -pathUp :: Int -> FilePath -> FilePath -pathUp n file = concat (replicate n "../") ++ file - -pathLevel :: FilePath -> Int -pathLevel = length . filter (=='/') - -idToFilePath :: HasId a => a -> FilePath -idToFilePath = idToFilePathWith ".html" - -idToFilePathWith :: HasId a => String -> a -> FilePath -idToFilePathWith suffix a = foldr (</>) (unqualified a ++ suffix) (qualifiers a) - -(</>) :: String -> FilePath -> FilePath -x </> y = x ++ "/" ++ y+ f c = [c]
+ src/Ideas/Encoding/Logging.hs view
@@ -0,0 +1,187 @@+{-# LANGUAGE CPP, FlexibleContexts #-} +----------------------------------------------------------------------------- +-- Copyright 2016, Ideas project team. This file is distributed under the +-- terms of the Apache License 2.0. For more information, see the files +-- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution. +----------------------------------------------------------------------------- +-- | +-- Maintainer : bastiaan.heeren@ou.nl +-- Stability : provisional +-- Portability : portable (depends on ghc) +-- +-- Facilities to create a log database +-- +----------------------------------------------------------------------------- + +module Ideas.Encoding.Logging + ( Record(..), addRequest, addState + , LogRef, newLogRef, noLogRef, changeLog + , logEnabled, logRecord, printLog + ) where + +import Data.IORef +import Data.Maybe +import Data.Time +import Ideas.Encoding.Request (Request, Schema(..)) +import Ideas.Service.State +import qualified Ideas.Encoding.Request as R + +#ifdef DB +import Data.List +import Database.HDBC +import Database.HDBC.Sqlite3 (connectSqlite3) +#endif + +type Diff = NominalDiffTime +type Time = UTCTime + +-- | The Record datatype is based on the Ideas Request Logging Schema version 2. +data Record = Record + { -- request attributes + service :: String -- name of feedback service + , exerciseid :: String -- exercise identifier + , source :: String -- tool/learning environment that makes request + , script :: String -- name of feedback script (for textual feedback) + , requestinfo :: String -- additional information from client (only for logging) + -- request format + , dataformat :: String -- xml, json + , encoding :: String -- options for encoding (e.g. OpenMath, string) + , -- grouping requests + userid :: String -- user identifier (e.g. student number) + , sessionid :: String -- session identifier (grouping requests for one task) + , taskid :: String -- task identifier (default: start term) + -- meta-information + , time :: Time -- date and time of request + , responsetime :: Diff -- time needed for processing request + , ipaddress :: String -- IP address of client + , binary :: String -- name of (cgi) binary that is being executed + , version :: String -- version (and revision) information + , errormsg :: String -- internal error message (default: empty string) + -- service info + , serviceinfo :: String -- summary of reply (customized for each service) + , ruleid :: String -- rule identifier (customized for each service) + -- raw data + , input :: String -- raw input (request) + , output :: String -- raw output (reply) + } + deriving Show + +record :: Record +record = Record "" "" "" "" "" "" "" "" "" "" t0 0 "" "" "" "" "" "" "" "" + where t0 = UTCTime (toEnum 0) 0 + +makeRecord :: IO Record +makeRecord = do + now <- getCurrentTime + return record { time = now } + +-- | Add record information from the Request datatype +addRequest :: Request -> Record -> Record +addRequest req r = r + { service = maybe (service r) show (R.serviceId req) + , exerciseid = maybe (exerciseid r) show (R.exerciseId req) + , source = fromMaybe (source r) (R.source req) + , script = fromMaybe (script r) (R.feedbackScript req) + , requestinfo = fromMaybe (requestinfo r) (R.requestInfo req) + , dataformat = show (R.dataformat req) + , encoding = show (R.encoding req) + , binary = fromMaybe (binary r) (R.cgiBinary req) + } + +-- | Add record information from the state (userid, sessionid, taskid) +addState :: State a -> Record -> Record +addState st r = r + { userid = fromMaybe (userid r) (stateUser st) + , sessionid = fromMaybe (sessionid r) (stateSession st) + , taskid = fromMaybe (taskid r) (stateStartTerm st) + } + +--------------------------------------------------------------------- + +newtype LogRef = L { mref :: Maybe (IORef Record) } + +noLogRef :: LogRef +noLogRef = L Nothing + +newLogRef :: IO LogRef +newLogRef = do + r <- makeRecord + ref <- newIORef r + return (L (Just ref)) + +getRecord :: LogRef -> IO Record +getRecord = maybe (return record) readIORef . mref + +changeLog :: LogRef -> (Record -> Record) -> IO () +changeLog = maybe (\_ -> return ()) modifyIORef . mref + +printLog :: LogRef -> IO () +printLog logRef = do + putStrLn "-- log information" + getRecord logRef >>= print + +-------------------------------------------------------------------------------- + +logEnabled :: Bool +logRecord :: Schema -> LogRef -> IO () + +#ifdef DB +logEnabled = True +logRecord schema logRef = + case schema of + V1 -> connectSqlite3 "service.db" >>= logRecordWith V1 logRef + V2 -> connectSqlite3 "requests.db" >>= logRecordWith V2 logRef + NoLogging -> return () +#else +-- without logging +logEnabled = False +logRecord _ _ = return () +#endif + +-------------------------------------------------------------------------------- + +#ifdef DB +nameOfTable :: Schema -> String +nameOfTable V1 = "log" +nameOfTable _ = "requests" + +columnsInTable :: Schema -> Record -> [SqlValue] +columnsInTable V1 = values_v1 +columnsInTable _ = values_v2 + +values_v1 :: Record -> [SqlValue] +values_v1 r = + let get f = toSql (f r) + in [ get service, get exerciseid, get source, get dataformat, get encoding + , get input, get output, get ipaddress, get time, get responsetime + ] + +values_v2 :: Record -> [SqlValue] +values_v2 r = + let get f = toSql (f r) + in [ get service, get exerciseid, get source, get script, get requestinfo + , get dataformat, get encoding, get userid, get sessionid, get taskid + , get time, get responsetime, get ipaddress, get binary, get version + , get errormsg, get serviceinfo, get ruleid, get input, get output + ] + +logRecordWith :: IConnection c => Schema -> LogRef -> c -> IO () +logRecordWith schema logRef conn = do + -- calculate duration + r <- getRecord logRef + end <- getCurrentTime + let diff = diffUTCTime end (time r) + -- insert data into database + insertRecord schema r {responsetime = diff} conn + -- close the connection to the database + disconnect conn + `catchSql` \err -> + putStrLn $ "Error in logging to database: " ++ show err + +insertRecord :: IConnection c => Schema -> Record -> c -> IO () +insertRecord schema r conn = + let cols = columnsInTable schema r + pars = "(" ++ intercalate "," (replicate (length cols) "?") ++ ")" + stm = "INSERT INTO " ++ nameOfTable schema ++ " VALUES " ++ pars + in run conn stm cols >> commit conn +#endif
src/Ideas/Encoding/ModeJSON.hs view
@@ -18,22 +18,22 @@ import Data.Char import Data.Maybe import Ideas.Common.Library hiding (exerciseId) -import Ideas.Common.Utils (Some(..), timedSeconds) import Ideas.Encoding.DecoderJSON -import Ideas.Encoding.Encoder (makeOptions) import Ideas.Encoding.EncoderJSON import Ideas.Encoding.Evaluator -import Ideas.Main.Logging (LogRef, changeLog, errormsg) +import Ideas.Encoding.Logging (LogRef, changeLog, errormsg) +import Ideas.Encoding.Options (Options, makeOptions, maxTime, cgiBin) +import Ideas.Encoding.Request import Ideas.Service.DomainReasoner -import Ideas.Service.Request import Ideas.Text.JSON +import Ideas.Utils.Prelude (timedSeconds) -processJSON :: Maybe Int -> Maybe String -> DomainReasoner -> LogRef -> String -> IO (Request, String, String) -processJSON maxTime cgiBin dr logRef input = do - json <- either fail return (parseJSON input) - req <- jsonRequest cgiBin json +processJSON :: Options -> DomainReasoner -> LogRef -> String -> IO (Request, String, String) +processJSON options dr logRef txt = do + json <- either fail return (parseJSON txt) + req <- jsonRequest options json resp <- jsonRPC json $ \fun arg -> - maybe id timedSeconds maxTime (myHandler dr logRef req fun arg) + maybe id timedSeconds (maxTime options) (myHandler options dr logRef req fun arg) unless (responseError resp == Null) $ changeLog logRef (\r -> r {errormsg = show (responseError resp)}) let f = if compactOutput req then compactJSON else show @@ -51,7 +51,7 @@ Array (hd:_) -> extractExerciseId hd _ -> fail "no code" where - p c = not (isAlphaNum c || isSpace c || c `elem` ".-") + p c = not (isAlphaNum c || isSpace c || c `elem` ".-_") addVersion :: String -> JSON -> JSON addVersion str json = @@ -61,32 +61,32 @@ where info = ("version", String str) -jsonRequest :: Monad m => Maybe String -> JSON -> m Request -jsonRequest cgiBin json = do +jsonRequest :: Monad m => Options -> JSON -> m Request +jsonRequest options json = do let exId = lookupM "params" json >>= extractExerciseId srv <- stringOption "method" json newId src <- stringOption "source" json id rinf <- stringOption "requestinfo" json id - seed <- stringOptionM "randomseed" json (defaultSeed cgiBin) (return . readM) + seed <- stringOptionM "randomseed" json (defaultSeed options) (return . readM) enc <- stringOptionM "encoding" json [] readEncoding - sch <- stringOptionM "logging" json Nothing (liftM Just . readSchema) - return emptyRequest + sch <- stringOptionM "logging" json Nothing (fmap Just . readSchema) + return mempty { serviceId = srv , exerciseId = exId , source = src - , cgiBinary = cgiBin + , cgiBinary = cgiBin options , requestInfo = rinf , logSchema = sch , randomSeed = seed - , dataformat = JSON + , dataformat = Just JSON , encoding = enc } -- Use a fixed seed for random number generation for command-line invocations -defaultSeed :: Maybe String -> Maybe Int -defaultSeed cgiBin - | isJust cgiBin = Nothing - | otherwise = Just 2805 -- magic number +defaultSeed :: Options -> Maybe Int +defaultSeed options + | isJust (cgiBin options) = Nothing + | otherwise = Just 2805 -- magic number stringOption :: Monad m => String -> JSON -> (String -> a) -> m (Maybe a) stringOption attr json f = stringOptionM attr json Nothing (return . Just . f) @@ -98,11 +98,15 @@ Just _ -> fail $ "Invalid value for " ++ attr ++ " (expecting string)" Nothing -> return a -myHandler :: DomainReasoner -> LogRef -> Request -> RPCHandler -myHandler dr logRef request fun json = do +myHandler :: Options -> DomainReasoner -> LogRef -> Request -> RPCHandler +myHandler opt1 dr logRef request fun json = do srv <- findService dr (newId fun) - Some options <- makeOptions dr request - evalService logRef options jsonEvaluator srv json + Some ex <- case exerciseId request of + Just a -> findExercise dr a + Nothing -> return (Some emptyExercise) + opt2 <- makeOptions dr ex request + let options = opt1 <> opt2 + evalService logRef ex options jsonEvaluator srv json jsonEvaluator :: Evaluator a JSON JSON jsonEvaluator = Evaluator jsonDecoder jsonEncoder
src/Ideas/Encoding/ModeXML.hs view
@@ -16,25 +16,25 @@ import Control.Exception import Control.Monad -import Ideas.Common.Library hiding (exerciseId, (:=)) -import Ideas.Common.Utils (Some(..), timedSeconds) +import Ideas.Common.Library hiding (exerciseId) import Ideas.Encoding.DecoderXML -import Ideas.Encoding.Encoder (makeOptions) import Ideas.Encoding.EncoderHTML import Ideas.Encoding.EncoderXML import Ideas.Encoding.Evaluator -import Ideas.Main.Logging (LogRef, changeLog, errormsg) +import Ideas.Encoding.Logging (LogRef, changeLog, errormsg) +import Ideas.Encoding.Options (Options, makeOptions, maxTime, cgiBin) +import Ideas.Encoding.Request import Ideas.Service.DomainReasoner -import Ideas.Service.Request import Ideas.Text.HTML import Ideas.Text.XML +import Ideas.Utils.Prelude (timedSeconds) import System.IO.Error -processXML :: Maybe Int -> Maybe String -> DomainReasoner -> LogRef -> String -> IO (Request, String, String) -processXML maxTime cgiBin dr logRef input = do - xml <- either fail return (parseXML input) - req <- xmlRequest cgiBin xml - resp <- maybe id timedSeconds maxTime (xmlReply dr logRef req xml) +processXML :: Options -> DomainReasoner -> LogRef -> String -> IO (Request, String, String) +processXML options dr logRef txt = do + xml <- either fail return (parseXML txt) + req <- xmlRequest (cgiBin options) xml + resp <- maybe id timedSeconds (maxTime options) (xmlReply options dr logRef req xml) `catch` handler let showXML | compactOutput req = compactXML | otherwise = show @@ -52,23 +52,23 @@ in xml { attributes = attributes xml ++ info } xmlRequest :: Monad m => Maybe String -> XML -> m Request -xmlRequest cgiBin xml = do +xmlRequest ms xml = do unless (name xml == "request") $ fail "expected xml tag request" enc <- case findAttribute "encoding" xml of Just s -> readEncoding s Nothing -> return [] - return emptyRequest + return mempty { serviceId = newId <$> findAttribute "service" xml , exerciseId = extractExerciseId xml , source = findAttribute "source" xml - , cgiBinary = cgiBin + , cgiBinary = ms , requestInfo = findAttribute "requestinfo" xml , logSchema = findAttribute "logging" xml >>= readSchema , feedbackScript = findAttribute "script" xml - , randomSeed = defaultSeed cgiBin $ + , randomSeed = defaultSeed ms $ findAttribute "randomseed" xml >>= readM - , dataformat = XML + , dataformat = Just XML , encoding = enc } @@ -77,22 +77,27 @@ defaultSeed Nothing Nothing = Just 2805 -- magic number defaultSeed _ m = m -xmlReply :: DomainReasoner -> LogRef -> Request -> XML -> IO XML -xmlReply dr logRef request xml = do +xmlReply :: Options -> DomainReasoner -> LogRef -> Request -> XML -> IO XML +xmlReply opt1 dr logRef request xml = do srv <- case serviceId request of Just a -> findService dr a Nothing -> fail "No service" - Some options <- makeOptions dr request + Some ex <- case exerciseId request of + Just a -> findExercise dr a + Nothing -> return (Some emptyExercise) + opt2 <- makeOptions dr ex request + let options = opt1 <> opt2 + if htmlOutput request -- HTML evaluator - then liftM toXML $ evalService logRef options (htmlEvaluator dr) srv xml + then toXML <$> evalService logRef ex options (htmlEvaluator dr) srv xml -- xml evaluator - else liftM resultOk $ evalService logRef options xmlEvaluator srv xml + else resultOk <$> evalService logRef ex options xmlEvaluator srv xml extractExerciseId :: Monad m => XML -> m Id -extractExerciseId = liftM newId . findAttribute "exerciseid" +extractExerciseId = fmap newId . findAttribute "exerciseid" resultOk :: XMLBuilder -> XML resultOk body = makeXML "reply" $
src/Ideas/Encoding/OpenMathSupport.hs view
@@ -21,10 +21,10 @@ import Data.Char import Data.List import Ideas.Common.Library -import Ideas.Common.Utils.Uniplate import Ideas.Text.OpenMath.Dictionary.Arith1 import Ideas.Text.OpenMath.Dictionary.Fns1 import Ideas.Text.OpenMath.Object +import Ideas.Utils.Uniplate import qualified Ideas.Text.OpenMath.Dictionary.List1 as OM import qualified Ideas.Text.OpenMath.Symbol as OM @@ -72,8 +72,8 @@ OMI n -> return (TNum n) OMF a -> return (TFloat a) OMA xs -> case xs of - OMS s:ys | s == OM.listSymbol -> liftM TList (mapM rec ys) - | otherwise -> liftM (function (newSymbol s)) (mapM rec ys) + OMS s:ys | s == OM.listSymbol -> TList <$> mapM rec ys + | otherwise -> function (newSymbol s) <$> mapM rec ys _ -> fail "Invalid OpenMath object" OMBIND binder xs body -> rec (OMA (binder:map OMV xs++[body]))
+ src/Ideas/Encoding/Options.hs view
@@ -0,0 +1,73 @@+----------------------------------------------------------------------------- +-- Copyright 2016, Ideas project team. This file is distributed under the +-- terms of the Apache License 2.0. For more information, see the files +-- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution. +----------------------------------------------------------------------------- +-- | +-- Maintainer : bastiaan.heeren@ou.nl +-- Stability : provisional +-- Portability : portable (depends on ghc) +-- +----------------------------------------------------------------------------- + +module Ideas.Encoding.Options + ( Options, makeOptions, optionBaseUrl + , script, request, qcGen, baseUrl, maxTime + , cgiBin, optionCgiBin, optionHtml + ) where + +import Control.Applicative +import Data.Monoid +import Ideas.Common.Library (Exercise, getId) +import Ideas.Encoding.Request +import Ideas.Service.DomainReasoner +import Ideas.Service.FeedbackScript.Parser (parseScriptSafe, Script) +import Test.QuickCheck.Random + +------------------------------------------------------------------- +-- Options + +cgiBin :: Options -> Maybe String +cgiBin = cgiBinary . request + +optionCgiBin :: String -> Options +optionCgiBin s = mempty {request = mempty {cgiBinary = Just s}} + +data Options = Options + { request :: Request -- meta-information about the request + , qcGen :: Maybe QCGen -- random number generator + , script :: Script -- feedback script + , baseUrl :: Maybe String -- for html-encoder's css and image files + , maxTime :: Maybe Int -- timeout for services, in seconds + } + +instance Monoid Options where + mempty = Options mempty Nothing mempty Nothing Nothing + mappend x y = Options + { request = request x <> request y + , qcGen = make qcGen + , script = script x <> script y + , baseUrl = make baseUrl + , maxTime = make maxTime + } + where + make f = f x <|> f y + +optionHtml :: Options +optionHtml = mempty + { request = mempty {encoding = [EncHTML]} } + +optionBaseUrl :: String -> Options +optionBaseUrl base = mempty {baseUrl = Just base} + +makeOptions :: DomainReasoner -> Exercise a -> Request -> IO Options +makeOptions dr ex req = do + gen <- maybe newQCGen (return . mkQCGen) (randomSeed req) + scr <- case feedbackScript req of + Just s -> parseScriptSafe s + Nothing -> defaultScript dr (getId ex) + return $ mempty + { request = req + , qcGen = Just gen + , script = scr + }
+ src/Ideas/Encoding/Request.hs view
@@ -0,0 +1,130 @@+----------------------------------------------------------------------------- +-- Copyright 2016, Ideas project team. This file is distributed under the +-- terms of the Apache License 2.0. For more information, see the files +-- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution. +----------------------------------------------------------------------------- +-- | +-- Maintainer : bastiaan.heeren@ou.nl +-- Stability : provisional +-- Portability : portable (depends on ghc) +-- +----------------------------------------------------------------------------- + +module Ideas.Encoding.Request where + +import Control.Applicative +import Data.Char +import Data.List +import Data.Maybe +import Ideas.Common.Library hiding (exerciseId) +import Ideas.Utils.Prelude + +data Request = Request + { serviceId :: Maybe Id + , exerciseId :: Maybe Id + , source :: Maybe String + , feedbackScript :: Maybe String + , requestInfo :: Maybe String + , cgiBinary :: Maybe String + , logSchema :: Maybe Schema + , randomSeed :: Maybe Int + , dataformat :: Maybe DataFormat -- default: XML + , encoding :: [Encoding] + } + +instance Monoid Request where + mempty = Request Nothing Nothing Nothing Nothing + Nothing Nothing Nothing Nothing Nothing [] + mappend x y = Request + { serviceId = make serviceId + , exerciseId = make exerciseId + , source = make source + , feedbackScript = make feedbackScript + , requestInfo = make requestInfo + , cgiBinary = make cgiBinary + , logSchema = make logSchema + , randomSeed = make randomSeed + , dataformat = make dataformat + , encoding = encoding x <> encoding y + } + where + make f = f x <|> f y + +data Schema = V1 | V2 | NoLogging deriving (Show, Eq) + +getSchema :: Request -> Schema +getSchema = fromMaybe V1 . logSchema -- log schema V1 is the default + +readSchema :: Monad m => String -> m Schema +readSchema s0 + | s == "v1" = return V1 + | s == "v2" = return V2 + | s `elem` ["false", "no"] = return NoLogging + | otherwise = fail "Unknown schema" + where + s = map toLower (filter isAlphaNum s0) + +data DataFormat = XML | JSON + deriving Show -- needed for LoggingDatabase + +data Encoding = EncHTML -- html page as output + | EncOpenMath -- encode terms in OpenMath + | EncString -- encode terms as strings + | EncCompact -- compact ouput + | EncPretty -- pretty output + | EncJSON -- encode terms in JSON + deriving Eq + +instance Show Encoding where + showList xs rest = intercalate "+" (map show xs) ++ rest + show EncHTML = "html" + show EncOpenMath = "openmath" + show EncString = "string" + show EncCompact = "compact" + show EncPretty = "pretty" + show EncJSON = "json" + +htmlOutput :: Request -> Bool +htmlOutput = (EncHTML `elem`) . encoding + +compactOutput :: Request -> Bool +compactOutput req = + case (EncCompact `elem` xs, EncPretty `elem` xs) of + (True, False) -> True + (False, True) -> False + _ -> isJust (cgiBinary req) + where + xs = encoding req + +useOpenMath :: Request -> Bool +useOpenMath r = + case dataformat r of + Just JSON -> False + _ -> all (`notElem` encoding r) [EncString, EncHTML] + +useJSONTerm :: Request -> Bool +useJSONTerm r = + case dataformat r of + Just JSON -> EncJSON `elem` encoding r + _ -> False + +useLogging :: Request -> Bool +useLogging = (EncHTML `notElem`) . encoding + +discoverDataFormat :: Monad m => String -> m DataFormat +discoverDataFormat xs = + case dropWhile isSpace xs of + '<':_ -> return XML + '{':_ -> return JSON + _ -> fail "Unknown data format" + +readEncoding :: Monad m => String -> m [Encoding] +readEncoding = mapM (f . map toLower) . splitsWithElem '+' + where + f "html" = return EncHTML + f "openmath" = return EncOpenMath + f "string" = return EncString + f "compact" = return EncCompact + f "pretty" = return EncPretty + f "json" = return EncJSON + f s = fail $ "Invalid encoding: " ++ s
src/Ideas/Encoding/RulePresenter.hs view
@@ -15,7 +15,6 @@ import Data.List import Data.Maybe import Ideas.Common.Library -import Ideas.Common.Utils (Some(..)) import Ideas.Text.HTML ruleToHTML :: Some Exercise -> Rule a -> HTMLBuilder
src/Ideas/Encoding/RulesInfo.hs view
@@ -16,7 +16,6 @@ import Data.Char import Ideas.Common.Library -import Ideas.Common.Utils (Some(..)) import Ideas.Encoding.OpenMathSupport (toOMOBJ) import Ideas.Text.OpenMath.FMP import Ideas.Text.OpenMath.Object
src/Ideas/Encoding/StrategyInfo.hs view
@@ -14,10 +14,10 @@ module Ideas.Encoding.StrategyInfo (strategyToXML) where -import Ideas.Common.CyclicTree import Ideas.Common.Id import Ideas.Common.Strategy.Abstract import Ideas.Common.Strategy.Configuration +import Ideas.Common.Strategy.CyclicTree import Ideas.Common.Strategy.StrategyTree (StrategyTree) import Ideas.Text.XML
− src/Ideas/Main/BlackBoxTests.hs
@@ -1,116 +0,0 @@------------------------------------------------------------------------------ --- Copyright 2016, Ideas project team. This file is distributed under the --- terms of the Apache License 2.0. For more information, see the files --- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution. ------------------------------------------------------------------------------ --- | --- Maintainer : bastiaan.heeren@ou.nl --- Stability : provisional --- Portability : portable (depends on ghc) --- ------------------------------------------------------------------------------ - -module Ideas.Main.BlackBoxTests (blackBoxTests) where - -import Control.Monad -import Data.Char -import Data.List -import Ideas.Common.Utils (snd3) -import Ideas.Common.Utils.TestSuite -import Ideas.Encoding.ModeJSON -import Ideas.Encoding.ModeXML -import Ideas.Main.Logging -import Ideas.Service.DomainReasoner -import Ideas.Service.Request -import System.Directory -import System.IO -import qualified Data.Algorithm.Diff as Diff - --- Returns the number of tests performed -blackBoxTests :: DomainReasoner -> String -> IO TestSuite -blackBoxTests dr path = do - -- analyse content - xs0 <- getDirectoryContents path - let (xml, xs1) = partition (".xml" `isSuffixOf`) xs0 - (json, xs2) = partition (".json" `isSuffixOf`) xs1 - xs3 = map (path </>) (filter ((/= ".") . take 1) xs2) - -- recursively visit subdirectories - subs <- filterM doesDirectoryExist xs3 - rest <- mapM (blackBoxTests dr) subs - return $ suite ("Directory " ++ simplerDirectory path) $ - [ doBlackBoxTest dr JSON (path </> x) - | x <- json - ] ++ - [ doBlackBoxTest dr XML (path </> x) - | x <- xml - ] ++ - rest - -doBlackBoxTest :: DomainReasoner -> DataFormat -> FilePath -> TestSuite -doBlackBoxTest dr format path = - assertMessageIO (stripDirectoryPart path) $ do - -- Comparing output with expected output - withFile path ReadMode $ \h1 -> do - hSetBinaryMode h1 True - txt <- hGetContents h1 - out <- case format of - JSON -> liftM snd3 (processJSON Nothing Nothing dr noLogRef txt) - XML -> liftM snd3 (processXML Nothing Nothing dr noLogRef txt) - withFile expPath ReadMode $ \h2 -> do - hSetBinaryMode h2 True - expt <- hGetContents h2 - -- Force evaluation of the result, to make sure that - -- all file handles are closed afterwards. - let list1 = prepare expt - list2 = prepare out - msg = unlines (path : diffs list1 list2) - if list1 == list2 then return mempty else do - force msg -- force evaluation of message before closing files - return (message msg) - where - expPath = baseOf path ++ ".exp" - baseOf = reverse . drop 1 . dropWhile (/= '.') . reverse - -force :: String -> IO () -force s | sum (map ord s) >= 0 = return () - | otherwise = error "force" - -prepare :: String -> [String] -prepare = filter (not . null) . lines . filter (/= '\r') . noVersion - where - noVersion s | "version\": \"" `isPrefixOf` s = - "version\": \"X" ++ dropWhile (/='"') (drop 11 s) - noVersion s | "version=\"" `isPrefixOf` s = - "version=\"X" ++ dropWhile (/='"') (drop 9 s) - noVersion (x:xs) = x:noVersion xs - noVersion [] = [] - -diffs :: [String] -> [String] -> [String] -diffs xs ys = concatMap f $ Diff.getDiff xs ys - where - f (Diff.First a) = ["- " ++ a] - f (Diff.Second a) = ["+ " ++ a] - f _ = [] - -simplerDirectory :: String -> String -simplerDirectory s - | "../" `isPrefixOf` s = simplerDirectory (drop 3 s) - | "test/" `isPrefixOf` s = simplerDirectory (drop 5 s) - | otherwise = s - -stripDirectoryPart :: String -> String -stripDirectoryPart = reverse . takeWhile (/= '/') . reverse - -(</>) :: FilePath -> FilePath -> FilePath -x </> y = x ++ "/" ++ y - -{- -logicConfluence :: IO () -logicConfluence = reportTest "logic rules" (isConfluent f rs) - where - f = normalizeWith ops . normalFormWith ops rs - ops = map makeCommutative Logic.logicOperators - rwrs = Logic.logicRules \\ [Logic.ruleOrOverAnd, Logic.ruleCommOr, Logic.ruleCommAnd] - rs = [ r | RewriteRule r <- concatMap transformations rwrs ] - -- eqs = bothWays [ r | RewriteRule r <- concatMap transformations Logic.logicRules ] --}
+ src/Ideas/Main/CmdLineOptions.hs view
@@ -0,0 +1,80 @@+----------------------------------------------------------------------------- +-- Copyright 2016, Ideas project team. This file is distributed under the +-- terms of the Apache License 2.0. For more information, see the files +-- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution. +----------------------------------------------------------------------------- +-- | +-- Maintainer : bastiaan.heeren@ou.nl +-- Stability : provisional +-- Portability : portable (depends on ghc) +-- +-- Command-Line Options +-- +----------------------------------------------------------------------------- + +module Ideas.Main.CmdLineOptions + ( CmdLineOption(..), getCmdLineOptions + , versionText, helpText, shortVersion, fullVersion + ) where + +import Data.Maybe +import Ideas.Encoding.Logging (logEnabled) +import Ideas.Main.Revision +import System.Console.GetOpt +import System.Environment +import System.Exit + +data CmdLineOption + = Version | Help | PrintLog + | InputFile String | Test FilePath + | MakeScriptFor String | AnalyzeScript FilePath + deriving Eq + +header :: String +header = + "IDEAS: Intelligent Domain-specific Exercise Assistants\n" ++ + "Copyright 2016, Open Universiteit Nederland\n" ++ + versionText ++ + "\n\nUsage: ideas [OPTION] (by default, CGI protocol)\n" ++ + "\nOptions:" + +versionText :: String +versionText = + "version " ++ ideasVersion ++ ", revision " ++ ideasRevision ++ + ", logging " ++ (if logEnabled then "enabled" else "disabled") + +helpText :: String +helpText = usageInfo header options + +fullVersion :: String +fullVersion = "version " ++ ideasVersion ++ " (revision " + ++ ideasRevision ++ ", " ++ ideasLastChanged ++ ")" + +shortVersion :: String +shortVersion = ideasVersion ++ " (" ++ ideasRevision ++ ")" + +options :: [OptDescr CmdLineOption] +options = + [ Option [] ["version"] (NoArg Version) "show version number" + , Option "?" ["help"] (NoArg Help) "show options" + , Option "" ["print-log"] (NoArg PrintLog) "print log information (for debugging)" + , Option "f" ["file"] fileArg "use input FILE as request" + , Option "" ["test"] testArg "run tests on directory (default: 'test')" + , Option "" ["make-script"] makeScrArg "generate feedback script for exercise" + , Option "" ["analyze-script"] analyzeScrArg "analyze feedback script and report errors" + ] + +fileArg, testArg, makeScrArg, analyzeScrArg :: ArgDescr CmdLineOption +fileArg = ReqArg InputFile "FILE" +testArg = OptArg (Test . fromMaybe "test") "DIR" +makeScrArg = ReqArg MakeScriptFor "ID" +analyzeScrArg = ReqArg AnalyzeScript "FILE" + +getCmdLineOptions :: IO [CmdLineOption] +getCmdLineOptions = do + args <- getArgs + case getOpt Permute options args of + (flags, [], []) -> return flags + (_, _, errs) -> do + putStrLn (concat errs ++ helpText) + exitFailure
src/Ideas/Main/Default.hs view
@@ -13,42 +13,45 @@ ----------------------------------------------------------------------------- module Ideas.Main.Default - ( defaultMain, defaultCGI + ( defaultMain, defaultMainWith, defaultCGI -- extra exports - , Some(..), serviceList, metaServiceList, Service + , serviceList, metaServiceList, Service , module Ideas.Service.DomainReasoner ) where import Control.Exception import Control.Monad import Data.Maybe -import Ideas.Common.Utils (Some(..)) -import Ideas.Common.Utils.TestSuite import Ideas.Encoding.ModeJSON (processJSON) import Ideas.Encoding.ModeXML (processXML) -import Ideas.Main.BlackBoxTests -import Ideas.Main.Documentation -import Ideas.Main.Options hiding (fullVersion) +import Ideas.Encoding.Options (Options, maxTime, optionCgiBin) +import Ideas.Encoding.Request +import Ideas.Main.CmdLineOptions hiding (fullVersion) import Ideas.Service.DomainReasoner import Ideas.Service.FeedbackScript.Analysis -import Ideas.Service.Request import Ideas.Service.ServiceList import Ideas.Service.Types (Service) +import Ideas.Utils.BlackBoxTests +import Ideas.Utils.TestSuite import Network.CGI import System.IO import System.IO.Error (ioeGetErrorString) -import qualified Ideas.Main.Logging as Log +import qualified Ideas.Encoding.Logging as Log +import qualified Ideas.Main.CmdLineOptions as Options defaultMain :: DomainReasoner -> IO () -defaultMain dr = do - flags <- getFlags - if null flags - then defaultCGI dr - else defaultCommandLine dr flags +defaultMain = defaultMainWith mempty +defaultMainWith :: Options -> DomainReasoner -> IO () +defaultMainWith options dr = do + cmdLineOptions <- getCmdLineOptions + if null cmdLineOptions + then defaultCGI options dr + else defaultCommandLine options (addVersion dr) cmdLineOptions + -- Invoked as a cgi binary -defaultCGI :: DomainReasoner -> IO () -defaultCGI dr = runCGI $ handleErrors $ do +defaultCGI :: Options -> DomainReasoner -> IO () +defaultCGI options dr = runCGI $ handleErrors $ do -- create a record for logging logRef <- liftIO Log.newLogRef -- query environment @@ -57,7 +60,7 @@ input <- inputOrDefault -- process request (req, txt, ctp) <- liftIO $ - process dr logRef (Just cgiBin) input + process (options <> optionCgiBin cgiBin) dr logRef input -- log request to database when (useLogging req) $ liftIO $ do Log.changeLog logRef $ \r -> Log.addRequest req r @@ -97,13 +100,13 @@ return (isJust maybeAcceptCT && not (null xs)) -- Invoked from command-line with flags -defaultCommandLine :: DomainReasoner -> [Flag] -> IO () -defaultCommandLine dr flags = do +defaultCommandLine :: Options -> DomainReasoner -> [CmdLineOption] -> IO () +defaultCommandLine options dr cmdLineOptions = do hSetBinaryMode stdout True - mapM_ doAction flags + mapM_ doAction cmdLineOptions where - doAction flag = - case flag of + doAction cmdLineOption = + case cmdLineOption of -- information Version -> putStrLn ("IDEAS, " ++ versionText) Help -> putStrLn helpText @@ -112,9 +115,9 @@ withBinaryFile file ReadMode $ \h -> do logRef <- liftIO Log.newLogRef input <- hGetContents h - (req, txt, _) <- process dr logRef Nothing input + (req, txt, _) <- process options dr logRef input putStrLn txt - when (PrintLog `elem` flags) $ do + when (PrintLog `elem` cmdLineOptions) $ do Log.changeLog logRef $ \r -> Log.addRequest req r { Log.ipaddress = "command-line" , Log.version = shortVersion @@ -124,25 +127,35 @@ Log.printLog logRef -- blackbox tests Test dir -> do - tests <- blackBoxTests dr dir + tests <- blackBoxTests (makeTestRunner dr) ["xml", "json"] dir result <- runTestSuiteResult True tests printSummary result - -- generate documentation pages - MakePages dir -> - makeDocumentation dr dir -- feedback scripts MakeScriptFor s -> makeScriptFor dr s AnalyzeScript file -> parseAndAnalyzeScript dr file PrintLog -> return () -process :: DomainReasoner -> Log.LogRef -> Maybe String -> String -> IO (Request, String, String) -process dr logRef cgiBin input = do +process :: Options -> DomainReasoner -> Log.LogRef -> String -> IO (Request, String, String) +process options dr logRef input = do format <- discoverDataFormat input - run format (Just 5) cgiBin dr logRef input + run format options {maxTime = Just 5} (addVersion dr) logRef input `catch` \ioe -> do let msg = "Error: " ++ ioeGetErrorString ioe Log.changeLog logRef (\r -> r { Log.errormsg = msg }) - return (emptyRequest, msg, "text/plain") + return (mempty, msg, "text/plain") where run XML = processXML - run JSON = processJSON+ run JSON = processJSON + +makeTestRunner :: DomainReasoner -> String -> IO String +makeTestRunner dr input = do + (_, out, _) <- process mempty dr Log.noLogRef input + return out + +addVersion :: DomainReasoner -> DomainReasoner +addVersion dr = dr + { version = update version Options.shortVersion + , fullVersion = update fullVersion Options.fullVersion + } + where + update f s = if null (f dr) then s else f dr
− src/Ideas/Main/Documentation.hs
@@ -1,62 +0,0 @@------------------------------------------------------------------------------ --- Copyright 2016, Ideas project team. This file is distributed under the --- terms of the Apache License 2.0. For more information, see the files --- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution. ------------------------------------------------------------------------------ --- | --- Maintainer : bastiaan.heeren@ou.nl --- Stability : provisional --- Portability : portable (depends on ghc) --- --- Manages links to information --- ------------------------------------------------------------------------------ - -module Ideas.Main.Documentation (makeDocumentation) where - -import Control.Monad -import Ideas.Common.Library -import Ideas.Common.Utils -import Ideas.Encoding.Encoder (run, simpleOptions) -import Ideas.Encoding.EncoderHTML -import Ideas.Encoding.LinkManager -import Ideas.Service.BasicServices -import Ideas.Service.DomainReasoner -import Ideas.Service.Types -import Ideas.Text.HTML -import System.Directory -import System.FilePath (takeDirectory) - -makeDocumentation :: DomainReasoner -> String -> IO () -makeDocumentation dr dir = do - putStrLn "Generating index pages" - makeIndex urlForIndex (dr ::: tDomainReasoner) - makeIndex urlForExercises (exercises dr ::: tList tSomeExercise) - makeIndex urlForServices (services dr ::: tList tService) - putStrLn "Generating service pages" - forM_ (services dr) $ \srv -> - makeIndex (`urlForService` srv) (srv ::: tService) - putStrLn "Generating exercise pages" - forM_ (exercises dr) $ \(Some ex) -> do - makeEx ex urlForExercise (ex ::: tExercise) - makeEx ex urlForStrategy (toStrategy (strategy ex) ::: tStrategy) - makeEx ex urlForRules (ruleset ex ::: tList tRule) - makeEx ex urlForExamples (map (second (inContext ex)) (examples ex) ::: tList (tPair tDifficulty tContext)) - makeEx ex urlForDerivations (exampleDerivations ex ::: tError (tList (tDerivation (tPair tRule tEnvironment) tContext))) - forM_ (ruleset ex) $ \r -> - make ex (urlForRule lm ex r) (r ::: tRule) - where - lm = staticLinks - makeIndex f = make emptyExercise (f lm) - makeEx ex f = make ex (f lm ex) - make ex url tv = do - let enc = htmlEncoderAt (pathLevel url) dr - html <- run enc (simpleOptions ex) tv - safeWrite (dir </> url) (showHTML html) - -safeWrite :: FilePath -> String -> IO () -safeWrite filename txt = do - let dirpart = takeDirectory filename - unless (null dirpart) (createDirectoryIfMissing True dirpart) - putStrLn $ "- " ++ filename - writeFile filename txt
− src/Ideas/Main/Logging.hs
@@ -1,187 +0,0 @@-{-# LANGUAGE CPP, FlexibleContexts #-} ------------------------------------------------------------------------------ --- Copyright 2016, Ideas project team. This file is distributed under the --- terms of the Apache License 2.0. For more information, see the files --- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution. ------------------------------------------------------------------------------ --- | --- Maintainer : bastiaan.heeren@ou.nl --- Stability : provisional --- Portability : portable (depends on ghc) --- --- Facilities to create a log database --- ------------------------------------------------------------------------------ - -module Ideas.Main.Logging - ( Record(..), addRequest, addState - , LogRef, newLogRef, noLogRef, changeLog - , logEnabled, logRecord, printLog - ) where - -import Data.IORef -import Data.Maybe -import Data.Time -import Ideas.Service.Request (Request, Schema(..)) -import Ideas.Service.State -import qualified Ideas.Service.Request as R - -#ifdef DB -import Data.List -import Database.HDBC -import Database.HDBC.Sqlite3 (connectSqlite3) -#endif - -type Diff = NominalDiffTime -type Time = UTCTime - --- | The Record datatype is based on the Ideas Request Logging Schema version 2. -data Record = Record - { -- request attributes - service :: String -- name of feedback service - , exerciseid :: String -- exercise identifier - , source :: String -- tool/learning environment that makes request - , script :: String -- name of feedback script (for textual feedback) - , requestinfo :: String -- additional information from client (only for logging) - -- request format - , dataformat :: String -- xml, json - , encoding :: String -- options for encoding (e.g. OpenMath, string) - , -- grouping requests - userid :: String -- user identifier (e.g. student number) - , sessionid :: String -- session identifier (grouping requests for one task) - , taskid :: String -- task identifier (default: start term) - -- meta-information - , time :: Time -- date and time of request - , responsetime :: Diff -- time needed for processing request - , ipaddress :: String -- IP address of client - , binary :: String -- name of (cgi) binary that is being executed - , version :: String -- version (and revision) information - , errormsg :: String -- internal error message (default: empty string) - -- service info - , serviceinfo :: String -- summary of reply (customized for each service) - , ruleid :: String -- rule identifier (customized for each service) - -- raw data - , input :: String -- raw input (request) - , output :: String -- raw output (reply) - } - deriving Show - -record :: Record -record = Record "" "" "" "" "" "" "" "" "" "" t0 0 "" "" "" "" "" "" "" "" - where t0 = UTCTime (toEnum 0) 0 - -makeRecord :: IO Record -makeRecord = do - now <- getCurrentTime - return record { time = now } - --- | Add record information from the Request datatype -addRequest :: Request -> Record -> Record -addRequest req r = r - { service = maybe (service r) show (R.serviceId req) - , exerciseid = maybe (exerciseid r) show (R.exerciseId req) - , source = fromMaybe (source r) (R.source req) - , script = fromMaybe (script r) (R.feedbackScript req) - , requestinfo = fromMaybe (requestinfo r) (R.requestInfo req) - , dataformat = show (R.dataformat req) - , encoding = show (R.encoding req) - , binary = fromMaybe (binary r) (R.cgiBinary req) - } - --- | Add record information from the state (userid, sessionid, taskid) -addState :: State a -> Record -> Record -addState st r = r - { userid = fromMaybe (userid r) (stateUser st) - , sessionid = fromMaybe (sessionid r) (stateSession st) - , taskid = fromMaybe (taskid r) (stateStartTerm st) - } - ---------------------------------------------------------------------- - -newtype LogRef = L { mref :: Maybe (IORef Record) } - -noLogRef :: LogRef -noLogRef = L Nothing - -newLogRef :: IO LogRef -newLogRef = do - r <- makeRecord - ref <- newIORef r - return (L (Just ref)) - -getRecord :: LogRef -> IO Record -getRecord = maybe (return record) readIORef . mref - -changeLog :: LogRef -> (Record -> Record) -> IO () -changeLog = maybe (\_ -> return ()) modifyIORef . mref - -printLog :: LogRef -> IO () -printLog logRef = do - putStrLn "-- log information" - getRecord logRef >>= print - --------------------------------------------------------------------------------- - -logEnabled :: Bool -logRecord :: Schema -> LogRef -> IO () - -#ifdef DB -logEnabled = True -logRecord schema logRef = - case schema of - V1 -> connectSqlite3 "service.db" >>= logRecordWith V1 logRef - V2 -> connectSqlite3 "requests.db" >>= logRecordWith V2 logRef - NoLogging -> return () -#else --- without logging -logEnabled = False -logRecord _ _ = return () -#endif - --------------------------------------------------------------------------------- - -#ifdef DB -nameOfTable :: Schema -> String -nameOfTable V1 = "log" -nameOfTable _ = "requests" - -columnsInTable :: Schema -> Record -> [SqlValue] -columnsInTable V1 = values_v1 -columnsInTable _ = values_v2 - -values_v1 :: Record -> [SqlValue] -values_v1 r = - let get f = toSql (f r) - in [ get service, get exerciseid, get source, get dataformat, get encoding - , get input, get output, get ipaddress, get time, get responsetime - ] - -values_v2 :: Record -> [SqlValue] -values_v2 r = - let get f = toSql (f r) - in [ get service, get exerciseid, get source, get script, get requestinfo - , get dataformat, get encoding, get userid, get sessionid, get taskid - , get time, get responsetime, get ipaddress, get binary, get version - , get errormsg, get serviceinfo, get ruleid, get input, get output - ] - -logRecordWith :: IConnection c => Schema -> LogRef -> c -> IO () -logRecordWith schema logRef conn = do - -- calculate duration - r <- getRecord logRef - end <- getCurrentTime - let diff = diffUTCTime end (time r) - -- insert data into database - insertRecord schema r {responsetime = diff} conn - -- close the connection to the database - disconnect conn - `catchSql` \err -> - putStrLn $ "Error in logging to database: " ++ show err - -insertRecord :: IConnection c => Schema -> Record -> c -> IO () -insertRecord schema r conn = - let cols = columnsInTable schema r - pars = "(" ++ intercalate "," (replicate (length cols) "?") ++ ")" - stm = "INSERT INTO " ++ nameOfTable schema ++ " VALUES " ++ pars - in run conn stm cols >> commit conn -#endif
− src/Ideas/Main/Options.hs
@@ -1,83 +0,0 @@------------------------------------------------------------------------------ --- Copyright 2016, Ideas project team. This file is distributed under the --- terms of the Apache License 2.0. For more information, see the files --- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution. ------------------------------------------------------------------------------ --- | --- Maintainer : bastiaan.heeren@ou.nl --- Stability : provisional --- Portability : portable (depends on ghc) --- --- Options and command-line flags for services --- ------------------------------------------------------------------------------ - -module Ideas.Main.Options - ( Flag(..), getFlags - , versionText, helpText, shortVersion, fullVersion - ) where - -import Data.Maybe -import Ideas.Main.Logging (logEnabled) -import Ideas.Main.Revision -import System.Console.GetOpt -import System.Environment -import System.Exit - -data Flag = Version | Help | PrintLog - | InputFile String - | MakePages FilePath | Test FilePath - | MakeScriptFor String | AnalyzeScript FilePath - - deriving Eq - -header :: String -header = - "IDEAS: Intelligent Domain-specific Exercise Assistants\n" ++ - "Copyright 2016, Open Universiteit Nederland\n" ++ - versionText ++ - "\n\nUsage: ideas [OPTION] (by default, CGI protocol)\n" ++ - "\nOptions:" - -versionText :: String -versionText = - "version " ++ ideasVersion ++ ", revision " ++ ideasRevision ++ - ", logging " ++ (if logEnabled then "enabled" else "disabled") - -helpText :: String -helpText = usageInfo header options - -fullVersion :: String -fullVersion = "version " ++ ideasVersion ++ " (revision " - ++ ideasRevision ++ ", " ++ ideasLastChanged ++ ")" - -shortVersion :: String -shortVersion = ideasVersion ++ " (" ++ ideasRevision ++ ")" - -options :: [OptDescr Flag] -options = - [ Option [] ["version"] (NoArg Version) "show version number" - , Option "?" ["help"] (NoArg Help) "show options" - , Option "" ["print-log"] (NoArg PrintLog) "print log information (for debugging)" - , Option "f" ["file"] fileArg "use input FILE as request" - , Option "" ["make-pages"] pagesArg "generate pages for exercises and services" - , Option "" ["test"] testArg "run tests on directory (default: 'test')" - , Option "" ["make-script"] makeScrArg "generate feedback script for exercise" - , Option "" ["analyze-script"] analyzeScrArg "analyze feedback script and report errors" - ] - -fileArg, testArg, pagesArg, makeScrArg, analyzeScrArg :: ArgDescr Flag -fileArg = ReqArg InputFile "FILE" -testArg = OptArg (Test . fromMaybe "test") "DIR" -pagesArg = OptArg (MakePages . fromMaybe "docs") "DIR" -makeScrArg = ReqArg MakeScriptFor "ID" -analyzeScrArg = ReqArg AnalyzeScript "FILE" - -getFlags :: IO [Flag] -getFlags = do - args <- getArgs - case getOpt Permute options args of - (flags, [], []) -> return flags - (_, _, errs) -> do - putStrLn (concat errs ++ helpText) - exitFailure
src/Ideas/Main/Revision.hs view
@@ -2,10 +2,10 @@ module Ideas.Main.Revision where ideasVersion :: String-ideasVersion = "1.5"+ideasVersion = "1.6" ideasRevision :: String-ideasRevision = "cfe6d70796113f07095f803981e1d2cc222d4b8e"+ideasRevision = "893c5ef99623f5741cb221bd14b52c17d133cc69" ideasLastChanged :: String-ideasLastChanged = "Thu May 26 20:50:01 2016 +0200"+ideasLastChanged = "Wed Dec 14 14:07:10 2016 +0100"
src/Ideas/Service/BasicServices.hs view
@@ -13,7 +13,7 @@ module Ideas.Service.BasicServices ( -- * Basic Services stepsremaining, findbuggyrules, allfirsts, solution - , onefirst, applicable, allapplications, apply, generate, create + , onefirst, onefinal, applicable, allapplications, apply, generate, create , StepInfo, tStepInfo, exampleDerivations, recognizeRule ) where @@ -22,10 +22,11 @@ import Data.Maybe import Ideas.Common.Library hiding (applicable, apply, ready) import Ideas.Common.Traversal.Navigator (downs, navigateTo) -import Ideas.Common.Utils (fst3) import Ideas.Service.State import Ideas.Service.Types +import Ideas.Utils.Prelude (fst3) import Test.QuickCheck.Random +import qualified Data.Set as S import qualified Ideas.Common.Classes as Apply import qualified Ideas.Common.Library as Library @@ -36,9 +37,9 @@ Nothing -> Left "No random term" create :: QCGen -> Exercise a -> String -> Maybe String -> Either String (State a) -create rng ex input userId = - case parser ex input of - Left err -> fail err +create rng ex txt userId = + case parser ex txt of + Left err -> Left err Right a | evalPredicate (Library.ready ex) a -> Left "Is ready" | evalPredicate (Library.suitable ex) a -> Right $ startState rng ex userId a @@ -101,6 +102,9 @@ Right (hd:_) -> Right hd Left msg -> Left msg +onefinal :: State a -> Either String (Context a) +onefinal = fmap lastTerm . solution Nothing + applicable :: Location -> State a -> [Rule (Context a)] applicable loc state = let p r = not (isBuggy r) && Apply.applicable r (setLocation loc (stateContext state)) @@ -145,8 +149,35 @@ ca = setLocation loc (stateContext state) applyOff = -- scenario 2: off-strategy case transApplyWith env (transformation r) ca of - (new, _):_ -> Right (state {stateContext = new, statePrefix = noPrefix}) - [] -> Left ("Cannot apply " ++ show r) + (new, _):_ -> Right (restart (state {stateContext = new, statePrefix = noPrefix})) + [] -> + -- first check the environment (exercise-specific property) + case environmentCheck of + Just msg -> + Left msg + Nothing -> + -- try to find a buggy rule + case siblingsFirst [ (br, envOut) | br <- ruleset (exercise state), isBuggy br, (_, envOut) <- transApplyWith env (transformation br) ca ] of + [] -> Left ("Cannot apply " ++ show r) + brs -> Left ("Buggy rule " ++ intercalate "+" (map pp brs)) + where + pp (br, envOut) + | noBindings envOut = show br + | otherwise = show br ++ " {" ++ show envOut ++ "}" + + siblingsFirst xs = ys ++ zs + where + (ys, zs) = partition (siblingInCommon r . fst) xs + + environmentCheck :: Maybe String + environmentCheck = do + p <- getProperty "environment-check" (exercise state) + p env + +siblingInCommon :: Rule a -> Rule a -> Bool +siblingInCommon r1 r2 = not (S.null (getSiblings r1 `S.intersection` getSiblings r2)) + where + getSiblings r = S.fromList (getId r : ruleSiblings r) stepsremaining :: State a -> Either String Int stepsremaining = mapSecond derivationLength . solution Nothing
src/Ideas/Service/Diagnose.hs view
@@ -15,6 +15,7 @@ module Ideas.Service.Diagnose ( Diagnosis(..), tDiagnosis, diagnose + , getState, getStateAndReady , difference, differenceEqual ) where @@ -58,19 +59,23 @@ f s xs | null xs = s | otherwise = s ++ "(" ++ intercalate "," xs ++ ")" -{- -newState :: Diagnosis a -> Maybe (State a) -newState diagnosis = - case diagnosis of + +getState :: Diagnosis a -> Maybe (State a) +getState = fmap fst . getStateAndReady + +getStateAndReady :: Diagnosis a -> Maybe (State a, Bool) +getStateAndReady d = + case d of + SyntaxError _ -> Nothing Buggy _ _ -> Nothing NotEquivalent _ -> Nothing - Similar _ s -> Just s - WrongRule _ s _ -> Just s - Expected _ s _ -> Just s - Detour _ s _ _ -> Just s - Correct _ s -> Just s - Unknown _ s -> Just s --} + Similar b s -> Just (s, b) + WrongRule b s _ -> Just (s, b) + Expected b s _ -> Just (s, b) + Detour b s _ _ -> Just (s, b) + Correct b s -> Just (s, b) + Unknown b s -> Just (s, b) + ---------------------------------------------------------------- -- The diagnose service
src/Ideas/Service/DomainReasoner.hs view
@@ -14,7 +14,7 @@ ( DomainReasoner(..), tDomainReasoner, newDomainReasoner , exercisesSorted, servicesSorted , findExercise, findService - , defaultScript -- , readScript + , defaultScript ) where import Data.List @@ -22,11 +22,9 @@ import Data.Monoid import Data.Ord import Ideas.Common.Library -import Ideas.Common.Utils -import Ideas.Common.Utils.TestSuite import Ideas.Service.FeedbackScript.Parser import Ideas.Service.Types -import qualified Ideas.Main.Options as Options +import Ideas.Utils.TestSuite ----------------------------------------------------------------------- -- Domain Reasoner data type @@ -75,11 +73,7 @@ ) newDomainReasoner :: IsId a => a -> DomainReasoner -newDomainReasoner a = mempty - { reasonerId = newId a - , version = Options.shortVersion - , fullVersion = Options.fullVersion - } +newDomainReasoner a = mempty {reasonerId = newId a} ----------------------------------------------------------------------- -- Domain Reasoner functions
src/Ideas/Service/FeedbackScript/Analysis.hs view
@@ -22,12 +22,11 @@ import Data.Either import Data.List import Ideas.Common.Library -import Ideas.Common.Utils (Some(..)) -import Ideas.Common.Utils.Uniplate import Ideas.Service.DomainReasoner import Ideas.Service.FeedbackScript.Parser import Ideas.Service.FeedbackScript.Run import Ideas.Service.FeedbackScript.Syntax +import Ideas.Utils.Uniplate makeScriptFor :: IsId a => DomainReasoner -> a -> IO () makeScriptFor dr exId = do
src/Ideas/Service/FeedbackScript/Parser.hs view
@@ -23,7 +23,7 @@ import Data.Monoid import Ideas.Common.Id import Ideas.Service.FeedbackScript.Syntax -import Ideas.Text.Parsing +import Ideas.Utils.Parsing import System.Directory import System.FilePath
src/Ideas/Service/FeedbackScript/Run.hs view
@@ -20,7 +20,6 @@ , eval ) where -import Control.Monad import Data.List import Data.Maybe import Ideas.Common.Library hiding (ready, Environment) @@ -53,8 +52,8 @@ , recognized = Nothing , diffPair = Nothing , before = f st - , after = liftM snd next >>= f - , afterText = liftM snd next >>= g + , after = fmap snd next >>= f + , afterText = fmap snd next >>= g } where f s = fmap (`build` stateTerm s) (hasTermView (exercise s)) @@ -72,7 +71,7 @@ eval env script = either (return . findIdRef) evalText where evalText :: Text -> Maybe Text - evalText = liftM mconcat . mapM unref . textItems + evalText = fmap mconcat . mapM unref . textItems where unref (TextRef a) | a == expectedId = fmap (findIdRef . getId) (expected env) @@ -126,12 +125,12 @@ case diagnosis of SyntaxError s -> const (makeText s) Buggy _ r -> makeWrong "buggy" env {recognized = Just r} - NotEquivalent s -> makeNotEq s "noteq" env + NotEquivalent s -> makeNotEq s "noteq" env Expected _ _ r -> makeOk "ok" env {recognized = Just r} WrongRule _ _ mr -> makeWrong "wrongrule" env {recognized = mr} Similar _ _ -> makeOk "same" env Detour _ _ _ r -> makeOk "detour" env {recognized = Just r} - Correct _ _ -> makeOk "unknown" env + Correct _ _ -> makeOk "correct" env Unknown _ _ -> makeOk "unknown" env where makeOk = makeDefault "Well done!" @@ -161,7 +160,7 @@ feedbackIds :: [Id] feedbackIds = map newId - ["same", "noteq", "unknown", "ok", "buggy", "detour", "wrongrule", "hint", "step", "label"] + ["same", "noteq", "correct", "unknown", "ok", "buggy", "detour", "wrongrule", "hint", "step", "label"] attributeIds :: [Id] attributeIds =
src/Ideas/Service/FeedbackScript/Syntax.hs view
@@ -22,7 +22,7 @@ import Data.List import Data.Maybe import Ideas.Common.Library -import Ideas.Common.Utils.Uniplate +import Ideas.Utils.Uniplate newtype Script = S { scriptDecls :: [Decl] }
src/Ideas/Service/FeedbackText.hs view
@@ -65,8 +65,8 @@ -- indicates whether the student is allowed to continue (True), or forced -- to go back to the previous state (False) submittext :: Script -> State a -> String -> (Message, State a) -submittext script old input = - case parser ex input of +submittext script old txt = + case parser ex txt of Left msg -> (M (Just False) (TextString msg), old) Right a -> feedbacktext script old (inContext ex a) Nothing where @@ -86,8 +86,8 @@ Unknown _ s -> (msg False, s) where diagnosis = diagnose old new motivationId - output = feedbackDiagnosis diagnosis env script - msg b = M (Just b) output + out = feedbackDiagnosis diagnosis env script + msg b = M (Just b) out ex = exercise old motivationRule = motivationId >>= getRule ex env = (newEnvironment old motivationRule)
src/Ideas/Service/ProblemDecomposition.hs view
@@ -18,9 +18,9 @@ import Data.Maybe import Ideas.Common.Library import Ideas.Common.Strategy.Symbol -import Ideas.Common.Utils (fst3) import Ideas.Service.State import Ideas.Service.Types +import Ideas.Utils.Prelude (fst3) problemDecomposition :: Maybe Id -> State a -> Maybe (Answer a) -> Either String (Reply a) problemDecomposition msloc state maybeAnswer
− src/Ideas/Service/Request.hs
@@ -1,115 +0,0 @@------------------------------------------------------------------------------ --- Copyright 2016, Ideas project team. This file is distributed under the --- terms of the Apache License 2.0. For more information, see the files --- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution. ------------------------------------------------------------------------------ --- | --- Maintainer : bastiaan.heeren@ou.nl --- Stability : provisional --- Portability : portable (depends on ghc) --- ------------------------------------------------------------------------------ - -module Ideas.Service.Request where - -import Data.Char -import Data.List -import Data.Maybe -import Ideas.Common.Library hiding (exerciseId) -import Ideas.Common.Utils - -data Request = Request - { serviceId :: Maybe Id - , exerciseId :: Maybe Id - , source :: Maybe String - , feedbackScript :: Maybe String - , requestInfo :: Maybe String - , cgiBinary :: Maybe String - , logSchema :: Maybe Schema - , randomSeed :: Maybe Int - , dataformat :: DataFormat - , encoding :: [Encoding] - } - -emptyRequest :: Request -emptyRequest = Request Nothing Nothing Nothing Nothing - Nothing Nothing Nothing Nothing XML [] - -data Schema = V1 | V2 | NoLogging deriving (Show, Eq) - -getSchema :: Request -> Schema -getSchema = fromMaybe V1 . logSchema -- log schema V1 is the default - -readSchema :: Monad m => String -> m Schema -readSchema s0 - | s == "v1" = return V1 - | s == "v2" = return V2 - | s `elem` ["false", "no"] = return NoLogging - | otherwise = fail "Unknown schema" - where - s = map toLower (filter isAlphaNum s0) - -data DataFormat = XML | JSON - deriving Show -- needed for LoggingDatabase - -data Encoding = EncHTML -- html page as output - | EncOpenMath -- encode terms in OpenMath - | EncString -- encode terms as strings - | EncCompact -- compact ouput - | EncPretty -- pretty output - | EncJSON -- encode terms in JSON - deriving Eq - -instance Show Encoding where - showList xs rest = intercalate "+" (map show xs) ++ rest - show EncHTML = "html" - show EncOpenMath = "openmath" - show EncString = "string" - show EncCompact = "compact" - show EncPretty = "pretty" - show EncJSON = "json" - -htmlOutput :: Request -> Bool -htmlOutput = (EncHTML `elem`) . encoding - -compactOutput :: Request -> Bool -compactOutput req = - case (EncCompact `elem` xs, EncPretty `elem` xs) of - (True, False) -> True - (False, True) -> False - _ -> isJust (cgiBinary req) - where - xs = encoding req - -useOpenMath :: Request -> Bool -useOpenMath r = - case dataformat r of - JSON -> False - XML -> all (`notElem` encoding r) [EncString, EncHTML] - -useJSONTerm :: Request -> Bool -useJSONTerm r = - case dataformat r of - JSON -> EncJSON `elem` encoding r - XML -> False - -useLogging :: Request -> Bool -useLogging = (EncHTML `notElem`) . encoding - -discoverDataFormat :: Monad m => String -> m DataFormat -discoverDataFormat xs = - case dropWhile isSpace xs of - '<':_ -> return XML - '{':_ -> return JSON - _ -> fail "Unknown data format" - -readEncoding :: Monad m => String -> m [Encoding] -readEncoding = mapM (f . map toLower) . splitsWithElem '+' - where - f "html" = return EncHTML - f "openmath" = return EncOpenMath - f "string" = return EncString - f "compact" = return EncCompact - f "pretty" = return EncPretty - f "json" = return EncJSON - f s = fail $ "Invalid encoding: " ++ s
src/Ideas/Service/ServiceList.hs view
@@ -14,13 +14,13 @@ import Ideas.Common.ExerciseTests import Ideas.Common.Library hiding (apply, applicable, suitable, ready) -import Ideas.Common.Utils.TestSuite hiding (Message) import Ideas.Service.BasicServices import Ideas.Service.DomainReasoner import Ideas.Service.FeedbackText import Ideas.Service.ProblemDecomposition (problemDecomposition) import Ideas.Service.State import Ideas.Service.Types +import Ideas.Utils.TestSuite hiding (Message) import qualified Ideas.Service.Diagnose as Diagnose import qualified Ideas.Service.ProblemDecomposition as ProblemDecomposition import qualified Ideas.Service.Submit as Submit @@ -31,7 +31,7 @@ serviceList :: [Service] serviceList = -- basic services - [ solutionS, derivationS, allfirstsS, onefirstS + [ solutionS, derivationS, allfirstsS, onefirstS, onefinalS , equivalenceS, similarityS, suitableS, finishedS, readyS , stepsremainingS, allapplicationsS , applyS, generateS, createS, applicableS @@ -81,6 +81,11 @@ \this rule are returned." $ onefirst ::: tState .-> tString :|: Tag "elem" (tPair tStepInfo tState) -- special tag for (legacy) xml encoding + +onefinalS :: Service +onefinalS = makeService "basic.onefinal" + "Returns a final term, after taking zero or more steps, by applying the strategy." $ + onefinal ::: tState .-> tError tContext equivalenceS :: Service equivalenceS = makeService "basic.equivalence"
src/Ideas/Service/Submit.hs view
@@ -14,7 +14,7 @@ ----------------------------------------------------------------------------- module Ideas.Service.Submit - ( submit, Result(..), tResult + ( submit, Result(..), tResult, getState ) where import Data.Maybe @@ -30,6 +30,15 @@ | Ok [Rule (Context a)] (State a) -- equivalent | Detour [Rule (Context a)] (State a) -- equivalent | Unknown (State a) -- equivalent + +getState :: Result a -> Maybe (State a) +getState r = + case r of + Buggy _ -> Nothing + NotEquivalent _ -> Nothing + Ok _ s -> Just s + Detour _ s -> Just s + Unknown s -> Just s fromDiagnose :: Diagnosis a -> Result a fromDiagnose diagnosis =
src/Ideas/Service/Types.hs view
@@ -34,11 +34,10 @@ import Data.Maybe import Data.Tree import Ideas.Common.Library -import Ideas.Common.Utils import Ideas.Service.FeedbackScript.Syntax import Ideas.Service.State import Test.QuickCheck.Random (QCGen) -import qualified Ideas.Common.Utils.TestSuite as TestSuite +import qualified Ideas.Utils.TestSuite as TestSuite ----------------------------------------------------------------------------- -- Services
src/Ideas/Text/HTML.hs view
@@ -59,7 +59,7 @@ | css <- styleSheets page ] , mconcat - [ tag "script" ("src" .=. js) + [ element "script" ["src" .=. js, "type" .=. "text/javascript", string " "] | js <- scripts page ] ]
src/Ideas/Text/JSON.hs view
@@ -26,7 +26,7 @@ import Control.Monad import Data.List (intersperse) import Data.Maybe -import Ideas.Text.Parsing hiding (string, char) +import Ideas.Utils.Parsing hiding (string, char) import System.IO.Error import Test.QuickCheck import Text.PrettyPrint.Leijen hiding ((<$>)) @@ -107,7 +107,7 @@ instance InJSON Int where toJSON = toJSON . toInteger - fromJSON = liftM fromInteger . fromJSON + fromJSON = fmap fromInteger . fromJSON instance InJSON Integer where toJSON = Number . I @@ -138,17 +138,17 @@ instance (InJSON a, InJSON b) => InJSON (a, b) where toJSON (a, b) = Array [toJSON a, toJSON b] - fromJSON (Array [a, b]) = liftM2 (,) (fromJSON a) (fromJSON b) + fromJSON (Array [a, b]) = (,) <$> fromJSON a <*> fromJSON b fromJSON _ = fail "expecting an array with 2 elements" instance (InJSON a, InJSON b, InJSON c) => InJSON (a, b, c) where toJSON (a, b, c) = Array [toJSON a, toJSON b, toJSON c] - fromJSON (Array [a, b, c]) = liftM3 (,,) (fromJSON a) (fromJSON b) (fromJSON c) + fromJSON (Array [a, b, c]) = (,,) <$> fromJSON a <*> fromJSON b <*> fromJSON c fromJSON _ = fail "expecting an array with 3 elements" instance (InJSON a, InJSON b, InJSON c, InJSON d) => InJSON (a, b, c, d) where toJSON (a, b, c, d) = Array [toJSON a, toJSON b, toJSON c, toJSON d] - fromJSON (Array [a, b, c, d]) = liftM4 (,,,) (fromJSON a) (fromJSON b) (fromJSON c) (fromJSON d) + fromJSON (Array [a, b, c, d]) = (,,,) <$> fromJSON a <*> fromJSON b <*> fromJSON c <*> fromJSON d fromJSON _ = fail "expecting an array with 4 elements" instance InJSON IOException where @@ -270,13 +270,13 @@ arbitrary = sized arbJSON instance Arbitrary Number where - arbitrary = oneof [liftM I arbitrary, liftM (D . fromInteger) arbitrary] + arbitrary = oneof [I <$> arbitrary, (D . fromInteger) <$> arbitrary] arbJSON :: Int -> Gen JSON arbJSON n | n == 0 = oneof - [ liftM Number arbitrary, liftM String myStringGen - , liftM Boolean arbitrary, return Null + [ Number <$> arbitrary, String <$> myStringGen + , Boolean <$> arbitrary, return Null ] | otherwise = oneof [ arbJSON 0
+ src/Ideas/Text/Latex.hs view
@@ -0,0 +1,75 @@+{-# LANGUAGE OverloadedStrings #-} +----------------------------------------------------------------------------- +-- Copyright 2016, Ideas project team. This file is distributed under the +-- terms of the Apache License 2.0. For more information, see the files +-- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution. +----------------------------------------------------------------------------- +-- | +-- Maintainer : bastiaan.heeren@ou.nl +-- Stability : provisional +-- Portability : portable (depends on ghc) +-- +-- Support for LaTeX. +-- +----------------------------------------------------------------------------- + +module Ideas.Text.Latex + ( Latex, ToLatex(..), (<>) + , array, commas, brackets, parens + , command + ) where + +import Data.List +import Data.Monoid +import Data.String + +newtype Latex = L { showLatex :: String } + +instance Show Latex where + show = showLatex + +instance IsString Latex where + fromString = L + +instance Monoid Latex where + mempty = L [] + L xs `mappend` L ys = L (mappend xs ys) + +class ToLatex a where + toLatex :: a -> Latex + toLatexPrec :: Int -> a -> Latex + toLatexList :: [a] -> Latex + -- default implementations + toLatex = toLatexPrec 0 + toLatexPrec = const toLatex + toLatexList = brackets . commas . map toLatex + {-# MINIMAL toLatex | toLatexPrec #-} + +instance ToLatex a => ToLatex [a] where + toLatex = toLatexList + toLatexPrec = const toLatexList + +instance ToLatex a => ToLatex (Maybe a) where + toLatexPrec = maybe mempty . toLatexPrec + +instance ToLatex Char where + toLatex = fromString . return + toLatexList = fromString + +instance ToLatex Int where + toLatex = fromString . show + +commas :: [Latex] -> Latex +commas = mconcat . intersperse ",\\:" + +brackets, parens :: Latex -> Latex +brackets s = "[" <> s <> "]" +parens s = "(" <> s <> ")" + +array :: String -> [[Latex]] -> Latex +array s rows = "\\begin{array}{" <> fromString s <> "}" + <> mconcat (intersperse "\\\\" (map (mconcat . intersperse " & ") rows)) + <> "\\end{array}" + +command :: String -> Latex +command s = toLatex ("\\" ++ s ++ " ")
src/Ideas/Text/OpenMath/Object.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE DeriveDataTypeable #-} ----------------------------------------------------------------------------- -- Copyright 2016, Ideas project team. This file is distributed under the -- terms of the Apache License 2.0. For more information, see the files @@ -19,7 +18,6 @@ import Data.Generics.Uniplate.Direct hiding (children) import Data.List (nub) import Data.Maybe -import Data.Typeable import Ideas.Text.OpenMath.Symbol import Ideas.Text.XML @@ -30,7 +28,7 @@ | OMS Symbol | OMA [OMOBJ] | OMBIND OMOBJ [String] OMOBJ - deriving (Show, Eq, Typeable) + deriving (Show, Eq) instance InXML OMOBJ where toXML = omobj2xml @@ -63,7 +61,9 @@ return (OMA ys) [] | name xml == "OMS" -> do - let mcd = findAttribute "cd" xml + let mcd = case findAttribute "cd" xml of + Just "unknown" -> Nothing + this -> this n <- findAttribute "name" xml return (OMS (mcd, n))
src/Ideas/Text/OpenMath/Tests.hs view
@@ -34,15 +34,15 @@ relation1List ++ transc1List rec 0 = frequency - [ (1, liftM OMI arbitrary) - , (1, liftM (\n -> OMF (fromInteger n / 1000)) arbitrary) - , (1, liftM OMV arbitrary) + [ (1, OMI <$> arbitrary) + , (1, (\n -> OMF (fromInteger n / 1000)) <$> arbitrary) + , (1, OMV <$> arbitrary) , (5, elements $ map OMS symbols) ] rec n = frequency [ (1, rec 0) - , (3, choose (1,4) >>= liftM OMA . (`replicateM` f)) - , (1, liftM3 OMBIND f arbitrary f) + , (3, choose (1,4) >>= fmap OMA . (`replicateM` f)) + , (1, OMBIND <$> f <*> arbitrary <*> f) ] where f = rec (n `div` 2)
− src/Ideas/Text/Parsing.hs
@@ -1,120 +0,0 @@------------------------------------------------------------------------------ --- Copyright 2016, Ideas project team. This file is distributed under the --- terms of the Apache License 2.0. For more information, see the files --- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution. ------------------------------------------------------------------------------ --- | --- Maintainer : bastiaan.heeren@ou.nl --- Stability : provisional --- Portability : portable (depends on ghc) --- --- Utility functions for parsing with Parsec library --- ------------------------------------------------------------------------------ - -module Ideas.Text.Parsing - ( module Export - , (<*>), (*>), (<*), (<$>), (<$), (<**>) - , parseSimple, complete, skip, (<..>), ranges, stopOn - , naturalOrFloat, float - , UnbalancedError(..), balanced - ) where - -import Control.Applicative hiding ((<|>)) -import Control.Arrow -import Control.Monad -import Data.Char -import Data.List -import Text.ParserCombinators.Parsec as Export -import Text.ParserCombinators.Parsec.Expr as Export -import Text.ParserCombinators.Parsec.Language as Export -import Text.ParserCombinators.Parsec.Pos - -parseSimple :: Parser a -> String -> Either String a -parseSimple p = left show . runParser (complete p) () "" - -complete :: Parser a -> Parser a -complete p = spaces *> (p <* eof) - -skip :: Parser a -> Parser () -skip = void - --- Like the combinator from parser, except that for doubles --- the read instance is used. This is a more precies representation --- of the double (e.g., 1.413 is not 1.413000000001). -naturalOrFloat :: Parser (Either Integer Double) -naturalOrFloat = do - a <- num - b <- option "" ((:) <$> char '.' <*> nat) - c <- option "" ((:) <$> oneOf "eE" <*> num) - spaces - case reads (a++b++c) of - _ | null b && null c -> - case a of - '-':xs -> return (Left (negate (readInt xs))) - xs -> return (Left (readInt xs)) - [(d, [])] -> return (Right d) - _ -> fail "not a float" - where - nat = many1 digit - num = maybe id (:) <$> optionMaybe (char '-') <*> nat - readInt = foldl' op 0 -- ' - op a b = a*10+fromIntegral (ord b)-48 - -float :: Parser Double -float = do - a <- nat - b <- option "" ((:) <$> char '.' <*> nat) - c <- option "" ((:) <$> oneOf "eE" <*> num) - case reads (a++b++c) of - [(d, [])] -> return d - _ -> fail "not a float" - where - nat = many1 digit - num = (:) <$> char '-' <*> nat - -infix 6 <..> - -(<..>) :: Char -> Char -> Parser Char -x <..> y = satisfy (\c -> c >= x && c <= y) - -ranges :: [(Char, Char)] -> Parser Char -ranges xs = choice [ a <..> b | (a, b) <- xs ] - --- return in local function f needed for backwards compatibility -stopOn :: [String] -> Parser String -stopOn ys = rec - where - stop = choice (map f ys) - f x = try (string x >> return ' ') - rec = (:) <$ notFollowedBy stop <*> anyChar <*> rec - <|> return [] - --- simple function for finding unbalanced pairs (e.g. parentheses) -balanced :: [(Char, Char)] -> String -> Maybe UnbalancedError -balanced table = run (initialPos "") [] - where - run _ [] [] = Nothing - run _ ((pos, c):_) [] = return (NotClosed pos c) - run pos stack (x:xs) - | x `elem` opens = - run next ((pos, x):stack) xs - | x `elem` closes = - case stack of - (_, y):rest | Just x == lookup y table -> run next rest xs - _ -> return (NotOpened pos x) - | otherwise = - run next stack xs - where - next = updatePosChar pos x - - (opens, closes) = unzip table - -data UnbalancedError = NotClosed SourcePos Char - | NotOpened SourcePos Char - -instance Show UnbalancedError where - show (NotClosed pos c) = - show pos ++ ": Opening symbol " ++ [c] ++ " is not closed" - show (NotOpened pos c) = - show pos ++ ": Closing symbol " ++ [c] ++ " has no matching symbol"
src/Ideas/Text/UTF8.hs view
@@ -35,11 +35,11 @@ -- | Encode a string to UTF8 format (monadic) encodeM :: Monad m => String -> m String -encodeM = liftM (map chr . concat) . mapM (toUTF8 . ord) +encodeM = fmap (map chr . concat) . mapM (toUTF8 . ord) -- | Decode an UTF8 format string to unicode points (monadic) decodeM :: Monad m => String -> m String -decodeM = liftM (map chr) . fromUTF8 . map ord +decodeM = fmap (map chr) . fromUTF8 . map ord -- | Test whether the argument is a proper UTF8 string isUTF8 :: String -> Bool @@ -110,7 +110,7 @@ propEncoding = forAll (sized gen) valid where gen n = replicateM n someChar - someChar = liftM chr $ oneof + someChar = chr <$> oneof -- To get a nice distribution over the number of bytes used -- in the encoding [ choose (0, 127), choose (128, 2047)
src/Ideas/Text/XML.hs view
@@ -134,9 +134,12 @@ escape :: String -> String escape = concatMap f where - f '<' = "<" - f '>' = ">" - f '&' = "&" + f '<' = "<" + f '>' = ">" + f '&' = "&" + f '"' = """ + f '\'' = "'" + f '\n' = " " f c = [c] trim :: String -> String
src/Ideas/Text/XML/Document.hs view
@@ -32,7 +32,7 @@ data Reference = CharRef Int | EntityRef String -data Parameter = Parameter String +newtype Parameter = Parameter String data XMLDoc = XMLDoc { versionInfo :: Maybe String
src/Ideas/Text/XML/Interface.hs view
@@ -21,10 +21,10 @@ import Control.Arrow import Data.Char (chr, ord) import Data.Maybe -import Ideas.Text.Parsing (parseSimple) import Ideas.Text.XML.Document (Name, prettyElement) import Ideas.Text.XML.Parser (document) import Ideas.Text.XML.Unicode (decoding) +import Ideas.Utils.Parsing (parseSimple) import qualified Ideas.Text.XML.Document as D data Element = Element
src/Ideas/Text/XML/Parser.hs view
@@ -21,9 +21,9 @@ import Data.Char (toUpper, ord, isSpace) import Data.List (foldl') -- ' import Data.Maybe (catMaybes) -import Ideas.Text.Parsing hiding (digit, letter, space) import Ideas.Text.XML.Document hiding (versionInfo, name, content) import Ideas.Text.XML.Unicode +import Ideas.Utils.Parsing hiding (digit, letter, space) import Prelude hiding (seq) import qualified Ideas.Text.XML.Document as D
+ src/Ideas/Utils/BlackBoxTests.hs view
@@ -0,0 +1,110 @@+----------------------------------------------------------------------------- +-- Copyright 2016, Ideas project team. This file is distributed under the +-- terms of the Apache License 2.0. For more information, see the files +-- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution. +----------------------------------------------------------------------------- +-- | +-- Maintainer : bastiaan.heeren@ou.nl +-- Stability : provisional +-- Portability : portable (depends on ghc) +-- +----------------------------------------------------------------------------- + +module Ideas.Utils.BlackBoxTests (blackBoxTests, TestRunner) where + +import Control.Monad +import Data.Char +import Data.List +import Ideas.Utils.TestSuite +import System.Directory +import System.IO +import qualified Data.Algorithm.Diff as Diff + +type TestRunner = String -> IO String + +-- Returns the number of tests performed +blackBoxTests :: TestRunner -> [String] -> String -> IO TestSuite +blackBoxTests runner exts = rec + where + rec path = do + -- analyse content + xs0 <- getDirectoryContents path + let (files, xs1) = partition (`elemExts` exts) xs0 + xs2 = map (path </>) (filter ((/= ".") . take 1) xs1) + -- recursively visit subdirectories + subs <- filterM doesDirectoryExist xs2 + rest <- mapM rec subs + return $ suite ("Directory " ++ simplerDirectory path) $ + [ doBlackBoxTest runner (path </> x) + | x <- files + ] ++ rest + +doBlackBoxTest :: TestRunner -> FilePath -> TestSuite +doBlackBoxTest runner path = + assertMessageIO (stripDirectoryPart path) $ + -- Comparing output with expected output + withFile path ReadMode $ \h1 -> do + hSetBinaryMode h1 True + txt <- hGetContents h1 + out <- runner txt + withFile expPath ReadMode $ \h2 -> do + hSetBinaryMode h2 True + expt <- hGetContents h2 + -- Force evaluation of the result, to make sure that + -- all file handles are closed afterwards. + let list1 = prepare expt + list2 = prepare out + msg = unlines (path : diffs list1 list2) + if list1 == list2 then return mempty else do + force msg -- force evaluation of message before closing files + return (message msg) + where + expPath = baseOf path ++ ".exp" + baseOf = reverse . drop 1 . dropWhile (/= '.') . reverse + +elemExts :: FilePath -> [String] -> Bool +elemExts s = any (\xs -> ('.':xs) `isSuffixOf` s) + +force :: String -> IO () +force s | sum (map ord s) >= 0 = return () + | otherwise = error "force" + +prepare :: String -> [String] +prepare = filter (not . null) . lines . filter (/= '\r') . noVersion + where + noVersion s | "version\": \"" `isPrefixOf` s = + "version\": \"X" ++ dropWhile (/='"') (drop 11 s) + noVersion s | "version=\"" `isPrefixOf` s = + "version=\"X" ++ dropWhile (/='"') (drop 9 s) + noVersion (x:xs) = x:noVersion xs + noVersion [] = [] + +diffs :: [String] -> [String] -> [String] +diffs xs ys = concatMap f $ Diff.getDiff xs ys + where + f (Diff.First a) = ["- " ++ a] + f (Diff.Second a) = ["+ " ++ a] + f _ = [] + +simplerDirectory :: String -> String +simplerDirectory s + | "../" `isPrefixOf` s = simplerDirectory (drop 3 s) + | "test/" `isPrefixOf` s = simplerDirectory (drop 5 s) + | otherwise = s + +stripDirectoryPart :: String -> String +stripDirectoryPart = reverse . takeWhile (/= '/') . reverse + +(</>) :: FilePath -> FilePath -> FilePath +x </> y = x ++ "/" ++ y + +{- +logicConfluence :: IO () +logicConfluence = reportTest "logic rules" (isConfluent f rs) + where + f = normalizeWith ops . normalFormWith ops rs + ops = map makeCommutative Logic.logicOperators + rwrs = Logic.logicRules \\ [Logic.ruleOrOverAnd, Logic.ruleCommOr, Logic.ruleCommAnd] + rs = [ r | RewriteRule r <- concatMap transformations rwrs ] + -- eqs = bothWays [ r | RewriteRule r <- concatMap transformations Logic.logicRules ] +-}
+ src/Ideas/Utils/Parsing.hs view
@@ -0,0 +1,120 @@+----------------------------------------------------------------------------- +-- Copyright 2016, Ideas project team. This file is distributed under the +-- terms of the Apache License 2.0. For more information, see the files +-- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution. +----------------------------------------------------------------------------- +-- | +-- Maintainer : bastiaan.heeren@ou.nl +-- Stability : provisional +-- Portability : portable (depends on ghc) +-- +-- Utility functions for parsing with Parsec library +-- +----------------------------------------------------------------------------- + +module Ideas.Utils.Parsing + ( module Export + , (<*>), (*>), (<*), (<$>), (<$), (<**>) + , parseSimple, complete, skip, (<..>), ranges, stopOn + , naturalOrFloat, float + , UnbalancedError(..), balanced + ) where + +import Control.Applicative hiding ((<|>)) +import Control.Arrow +import Control.Monad +import Data.Char +import Data.List +import Text.ParserCombinators.Parsec as Export +import Text.ParserCombinators.Parsec.Expr as Export +import Text.ParserCombinators.Parsec.Language as Export +import Text.ParserCombinators.Parsec.Pos + +parseSimple :: Parser a -> String -> Either String a +parseSimple p = left show . runParser (complete p) () "" + +complete :: Parser a -> Parser a +complete p = spaces *> (p <* eof) + +skip :: Parser a -> Parser () +skip = void + +-- Like the combinator from parser, except that for doubles +-- the read instance is used. This is a more precies representation +-- of the double (e.g., 1.413 is not 1.413000000001). +naturalOrFloat :: Parser (Either Integer Double) +naturalOrFloat = do + a <- num + b <- option "" ((:) <$> char '.' <*> nat) + c <- option "" ((:) <$> oneOf "eE" <*> num) + spaces + case reads (a++b++c) of + _ | null b && null c -> + case a of + '-':xs -> return (Left (negate (readInt xs))) + xs -> return (Left (readInt xs)) + [(d, [])] -> return (Right d) + _ -> fail "not a float" + where + nat = many1 digit + num = maybe id (:) <$> optionMaybe (char '-') <*> nat + readInt = foldl' op 0 -- ' + op a b = a*10+fromIntegral (ord b)-48 + +float :: Parser Double +float = do + a <- nat + b <- option "" ((:) <$> char '.' <*> nat) + c <- option "" ((:) <$> oneOf "eE" <*> num) + case reads (a++b++c) of + [(d, [])] -> return d + _ -> fail "not a float" + where + nat = many1 digit + num = (:) <$> char '-' <*> nat + +infix 6 <..> + +(<..>) :: Char -> Char -> Parser Char +x <..> y = satisfy (\c -> c >= x && c <= y) + +ranges :: [(Char, Char)] -> Parser Char +ranges xs = choice [ a <..> b | (a, b) <- xs ] + +-- return in local function f needed for backwards compatibility +stopOn :: [String] -> Parser String +stopOn ys = rec + where + stop = choice (map f ys) + f x = try (string x >> return ' ') + rec = (:) <$ notFollowedBy stop <*> anyChar <*> rec + <|> return [] + +-- simple function for finding unbalanced pairs (e.g. parentheses) +balanced :: [(Char, Char)] -> String -> Maybe UnbalancedError +balanced table = run (initialPos "") [] + where + run _ [] [] = Nothing + run _ ((pos, c):_) [] = return (NotClosed pos c) + run pos stack (x:xs) + | x `elem` opens = + run next ((pos, x):stack) xs + | x `elem` closes = + case stack of + (_, y):rest | Just x == lookup y table -> run next rest xs + _ -> return (NotOpened pos x) + | otherwise = + run next stack xs + where + next = updatePosChar pos x + + (opens, closes) = unzip table + +data UnbalancedError = NotClosed SourcePos Char + | NotOpened SourcePos Char + +instance Show UnbalancedError where + show (NotClosed pos c) = + show pos ++ ": Opening symbol " ++ [c] ++ " is not closed" + show (NotOpened pos c) = + show pos ++ ": Closing symbol " ++ [c] ++ " has no matching symbol"
+ src/Ideas/Utils/Prelude.hs view
@@ -0,0 +1,127 @@+{-# LANGUAGE ExistentialQuantification #-} +----------------------------------------------------------------------------- +-- Copyright 2016, Ideas project team. This file is distributed under the +-- terms of the Apache License 2.0. For more information, see the files +-- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution. +----------------------------------------------------------------------------- +-- | +-- Maintainer : bastiaan.heeren@ou.nl +-- Stability : provisional +-- Portability : portable (depends on ghc) +-- +-- A collection of general utility functions +-- +----------------------------------------------------------------------------- + +module Ideas.Utils.Prelude + ( Some(..), ShowString(..), readInt, readM + , subsets, isSubsetOf + , cartesian, distinct, allsame + , fixpoint + , splitAtElem, splitsWithElem + , timedSeconds + , fst3, snd3, thd3 + , headM, findIndexM + , elementAt, changeAt, replaceAt + , list + ) where + +import Data.Char +import Data.List +import System.Timeout + +data Some f = forall a . Some (f a) + +newtype ShowString = ShowString { fromShowString :: String } + deriving (Eq, Ord) + +instance Show ShowString where + show = fromShowString + +instance Read ShowString where + readsPrec n s = [ (ShowString x, y) | (x, y) <- readsPrec n s ] + +readInt :: String -> Maybe Int +readInt xs + | null xs = Nothing + | any (not . isDigit) xs = Nothing + | otherwise = Just (foldl' (\a b -> a*10+ord b-48) 0 xs) -- ' + +readM :: (Monad m, Read a) => String -> m a +readM s = case reads s of + [(a, xs)] | all isSpace xs -> return a + _ -> fail ("no read: " ++ s) + +subsets :: [a] -> [[a]] +subsets = foldr op [[]] + where op a xs = xs ++ map (a:) xs + +isSubsetOf :: Eq a => [a] -> [a] -> Bool +isSubsetOf xs ys = all (`elem` ys) xs + +cartesian :: [a] -> [b] -> [(a, b)] +cartesian as bs = [ (a, b) | a <- as, b <- bs ] + +distinct :: Eq a => [a] -> Bool +distinct [] = True +distinct (x:xs) = notElem x xs && distinct xs + +allsame :: Eq a => [a] -> Bool +allsame [] = True +allsame (x:xs) = all (==x) xs + +fixpoint :: Eq a => (a -> a) -> a -> a +fixpoint f = rec . iterate f + where + rec [] = error "Ideas.Common.Utils: empty list" + rec (x:xs) + | x == head xs = x + | otherwise = rec xs + +splitAtElem :: Eq a => a -> [a] -> Maybe ([a], [a]) +splitAtElem c s = + case break (==c) s of + (xs, _:ys) -> Just (xs, ys) + _ -> Nothing + +splitsWithElem :: Eq a => a -> [a] -> [[a]] +splitsWithElem c s = + case splitAtElem c s of + Just (xs, ys) -> xs : splitsWithElem c ys + Nothing -> [s] + +timedSeconds :: Int -> IO a -> IO a +timedSeconds n m = timeout (n * 10^(6 :: Int)) m >>= + maybe (fail ("Timeout after " ++ show n ++ " seconds")) return + +fst3 :: (a, b, c) -> a +fst3 (x, _, _) = x + +snd3 :: (a, b, c) -> b +snd3 (_, x, _) = x + +thd3 :: (a, b, c) -> c +thd3 (_, _, x) = x + +-- generalized list functions (results in monad) +headM :: Monad m => [a] -> m a +headM (a:_) = return a +headM _ = fail "headM" + +findIndexM :: Monad m => (a -> Bool) -> [a] -> m Int +findIndexM p = maybe (fail "findIndexM") return . findIndex p + +elementAt :: Monad m => Int -> [a] -> m a +elementAt i = headM . drop i + +changeAt :: Monad m => Int -> (a -> a) -> [a] -> m [a] +changeAt i f as = + case splitAt i as of + (xs, y:ys) -> return (xs ++ f y : ys) + _ -> fail "changeAt" + +replaceAt :: Monad m => Int -> a -> [a] -> m [a] +replaceAt i = changeAt i . const + +list :: b -> ([a] -> b) -> [a] -> b +list b f xs = if null xs then b else f xs
+ src/Ideas/Utils/QuickCheck.hs view
@@ -0,0 +1,102 @@+----------------------------------------------------------------------------- +-- Copyright 2016, Ideas project team. This file is distributed under the +-- terms of the Apache License 2.0. For more information, see the files +-- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution. +----------------------------------------------------------------------------- +-- | +-- Maintainer : bastiaan.heeren@ou.nl +-- Stability : provisional +-- Portability : portable (depends on ghc) +-- +-- Extensions to the QuickCheck library +-- +----------------------------------------------------------------------------- + +module Ideas.Utils.QuickCheck + ( module Test.QuickCheck + -- * Data type + , ArbGen, generator, generators + -- * Constructors + , arbGen, constGen, constGens, unaryGen, unaryGens + , unaryArbGen, binaryGen, binaryGens, toArbGen + -- * Frequency combinators + , common, uncommon, rare, changeFrequency + ) where + +import Control.Arrow +import Control.Monad +import Data.Ratio +import Test.QuickCheck + +--------------------------------------------------------- +-- @ArbGen@ datatype + +newtype ArbGen a = AG [(Rational, (Int, Gen ([a] -> a)))] + +instance Monoid (ArbGen a) where + mempty = AG mempty + AG xs `mappend` AG ys = AG (xs `mappend` ys) + +generator :: ArbGen a -> Gen a +generator (AG pairs) = sized rec + where + factor = foldr (lcm . denominator . fst) 1 pairs + rec n = frequency (map make (select pairs)) + where + select + | n == 0 = filter ((==0) . fst . snd) + | otherwise = id + make (r, (a, gf)) = + let m = round (fromInteger factor*r) + xs = replicateM a $ rec $ n `div` 2 + in (m, gf <*> xs) + +generators :: [ArbGen a] -> Gen a +generators = generator . mconcat + +--------------------------------------------------------- +-- Constructors + +arbGen :: Arbitrary b => (b -> a) -> ArbGen a +arbGen f = newGen 0 ((const . f) <$> arbitrary) + +constGen :: a -> ArbGen a +constGen = pureGen 0 . const + +constGens :: [a] -> ArbGen a +constGens = mconcat . map constGen + +unaryGen :: (a -> a) -> ArbGen a +unaryGen f = pureGen 1 (f . head) + +unaryArbGen :: Arbitrary b => (b -> a -> a) -> ArbGen a +unaryArbGen f = newGen 1 $ (\a -> f a . head) <$> arbitrary + +unaryGens :: [a -> a] -> ArbGen a +unaryGens = mconcat . map unaryGen + +binaryGen :: (a -> a -> a) -> ArbGen a +binaryGen f = pureGen 2 (\xs -> f (head xs) (xs !! 1)) + +binaryGens :: [a -> a -> a] -> ArbGen a +binaryGens = mconcat . map binaryGen + +pureGen :: Int -> ([a] -> a) -> ArbGen a +pureGen n = newGen n . return + +toArbGen :: Gen a -> ArbGen a +toArbGen = newGen 0 . fmap const + +newGen :: Int -> Gen ([a] -> a) -> ArbGen a +newGen n f = AG [(1, (n, f))] + +--------------------------------------------------------- +-- Frequency combinators + +common, uncommon, rare :: ArbGen a -> ArbGen a +common = changeFrequency 2 +uncommon = changeFrequency (1/2) +rare = changeFrequency (1/5) + +changeFrequency :: Rational -> ArbGen a -> ArbGen a +changeFrequency r (AG xs) = AG (map (first (*r)) xs)
+ src/Ideas/Utils/StringRef.hs view
@@ -0,0 +1,134 @@+----------------------------------------------------------------------------- +-- Copyright 2016, Ideas project team. This file is distributed under the +-- terms of the Apache License 2.0. For more information, see the files +-- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution. +----------------------------------------------------------------------------- +-- | +-- Maintainer : bastiaan.heeren@ou.nl +-- Stability : provisional +-- Portability : portable (depends on ghc) +-- +-- References to Strings, proving a fast comparison implementation (Eq and +-- Ord) that uses a hash function. Code is based on Daan Leijen's Lazy +-- Virutal Machine (LVM) identifiers. +-- +----------------------------------------------------------------------------- + +module Ideas.Utils.StringRef + ( StringRef, stringRef, toString, tableStatus + ) where + +import Data.Bits +import Data.IORef +import Data.List +import System.IO.Unsafe +import qualified Data.IntMap as IM + +---------------------------------------------------------------- +-- StringRef datatype and instance declarations + +data StringRef = S !Int + deriving (Eq, Ord) + +---------------------------------------------------------------- +-- Hash table + +type HashTable = IM.IntMap [String] + +{-# NOINLINE tableRef #-} +tableRef :: IORef HashTable +tableRef = unsafePerformIO (newIORef IM.empty) + +---------------------------------------------------------------- +-- Conversion to and from strings + +stringRef :: String -> StringRef +stringRef s = unsafePerformIO $ do + let hash = hashString s + m <- readIORef tableRef + case IM.insertLookupWithKey (const combine) hash [s] m of + (Nothing, new) -> do + writeIORef tableRef new + return (S (encodeIndexZero hash)) + (Just old, new) -> + case elemIndex s old of + Just index -> + return (S (encode hash index)) + Nothing -> do + let index = length old + writeIORef tableRef new + return (S (encode hash index)) + +toString :: StringRef -> String +toString (S i) = unsafePerformIO $ do + m <- readIORef tableRef + case IM.lookup (extractHash i) m of + Just xs -> return (atIndex (extractIndex i) xs) + Nothing -> intErr "id not found" + +---------------------------------------------------------------- +-- Bit encoding + +encode :: Int -> Int -> Int +encode hash index = hash + index `shiftL` 12 + +encodeIndexZero :: Int -> Int +encodeIndexZero hash = hash + +extractHash :: Int -> Int +extractHash i = i `mod` 4096 + +extractIndex :: Int -> Int +extractIndex i = i `shiftR` 12 + +---------------------------------------------------------------- +-- Hash function + +-- simple hash function that performs quite good in practice +hashString :: String -> Int +hashString s = (f s `mod` prime) `mod` maxHash + where + f = foldl' next 0 -- ' strict fold + next n c = n*65599 + fromEnum c + prime = 32537 --65599 -- require: prime < maxHash + +maxHash :: Int +maxHash = 0xFFF -- 12 bits + +---------------------------------------------------------------- +-- Utility functions + +atIndex :: Int -> [a] -> a +atIndex 0 (x:_) = x +atIndex i (_:xs) = atIndex (i-1) xs +atIndex _ _ = intErr "corrupt symbol table" + +combine :: Eq a => [a] -> [a] -> [a] +combine [a] = rec + where + rec [] = [a] + rec this@(x:xs) + | a == x = this + | otherwise = x:rec xs +combine _ = intErr "combine" + +intErr :: String -> a +intErr s = error ("Internal error in Ideas.Common.StringRef: " ++ s) + +---------------------------------------------------------------- +-- Testing and debugging + +tableStatus :: IO String +tableStatus = readIORef tableRef >>= \m -> + let xs = map f (IM.assocs m) + f (i, ys) = '#' : show i ++ ": " ++ intercalate ", " (map g (frequency ys)) ++ + " [total = " ++ show (length ys) ++ "]" + g (a, n) | n == 1 = show a + | otherwise = show a ++ " (" ++ show n ++ ")" + in return $ unlines xs + +frequency :: Eq a => [a] -> [(a, Int)] +frequency [] = [] +frequency (x:xs) = + let (ys, zs) = partition (==x) xs + in (x, 1+length ys) : frequency zs
+ src/Ideas/Utils/TestSuite.hs view
@@ -0,0 +1,420 @@+----------------------------------------------------------------------------- +-- Copyright 2016, Ideas project team. This file is distributed under the +-- terms of the Apache License 2.0. For more information, see the files +-- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution. +----------------------------------------------------------------------------- +-- | +-- Maintainer : bastiaan.heeren@ou.nl +-- Stability : provisional +-- Portability : portable (depends on ghc) +-- +-- A lightweight wrapper for organizing tests (including QuickCheck tests). It +-- introduces the notion of a test suite, and it stores the test results for +-- later inspection (e.g., for the generation of a test report). A TestSuite +-- is a monoid. +-- +----------------------------------------------------------------------------- + +module Ideas.Utils.TestSuite + ( -- * TestSuite + TestSuite, module Data.Monoid + , suite, useProperty, usePropertyWith + , assertTrue, assertNull, assertEquals, assertIO + , assertMessage, assertMessageIO + , onlyWarnings, rateOnError + -- * Running a test suite + , runTestSuite, runTestSuiteResult + -- * Test Suite Result + , Result, subResults, findSubResult + , justOneSuite, allMessages, topMessages + , nrOfTests, nrOfErrors, nrOfWarnings + , timeInterval, makeSummary, printSummary + -- * Message + , Message, message, warning, messageLines + -- * Status + , Status, HasStatus(..) + , isError, isWarning, isOk + -- * Rating + , Rating, HasRating(..) + ) where + +import Control.Exception +import Control.Monad +import Data.Foldable (toList) +import Data.IORef +import Data.List +import Data.Maybe +import Data.Monoid +import Data.Time +import System.IO +import Test.QuickCheck hiding (Result) +import qualified Data.Sequence as S + +---------------------------------------------------------------- +-- Test Suite + +newtype TestSuite = TS (S.Seq Test) + +data Test = Case String (IO Message) + | Suite String TestSuite + +instance Monoid TestSuite where + mempty = TS mempty + TS xs `mappend` TS ys = TS (xs <> ys) + +tests :: TestSuite -> [Test] +tests (TS xs) = toList xs + +makeTestSuite :: Test -> TestSuite +makeTestSuite = TS . S.singleton + +---------------------------------------------------------------- +-- Test suite constructors + +-- | Construct a (named) test suite containing test cases and other suites +suite :: String -> [TestSuite] -> TestSuite +suite s = makeTestSuite . Suite s . mconcat + +-- | Turn a QuickCheck property into the test suite. The first argument is +-- a label for the property +useProperty :: Testable prop => String -> prop -> TestSuite +useProperty = flip usePropertyWith stdArgs + +-- | Turn a QuickCheck property into the test suite, also providing a test +-- configuration (Args) +usePropertyWith :: Testable prop => String -> Args -> prop -> TestSuite +usePropertyWith s args = + makeTestSuite . Case s . fmap make . quickCheckWithResult args {chatty=False} + where + make qc = + case qc of + Success {} -> + mempty + Failure {reason = msg} -> + message msg + NoExpectedFailure {} -> + message "no expected failure" + GaveUp {numTests = i} -> + warning ("passed only " ++ show i ++ " tests") + InsufficientCoverage {numTests = i} -> + warning ("only performed " ++ show i ++ " tests") + +assertTrue :: String -> Bool -> TestSuite +assertTrue s = assertIO s . return + +assertNull :: Show a => String -> [a] -> TestSuite +assertNull s xs = assertMessages s (null xs) (map show xs) + +assertEquals :: (Eq a, Show a) => String -> a -> a -> TestSuite +assertEquals s x y = assertMessage s (x==y) $ + "not equal " ++ show x ++ " and " ++ show y + +assertMessage :: String -> Bool -> String -> TestSuite +assertMessage s b = assertMessages s b . return + +assertMessages :: String -> Bool -> [String] -> TestSuite +assertMessages s b xs = makeTestSuite . Case s $ return $ + if b then mempty else mconcat (map message xs) + +assertIO :: String -> IO Bool -> TestSuite +assertIO s = makeTestSuite . Case s . fmap f + where + f b = if b then mempty else message "assertion failed" + +assertMessageIO :: String -> IO Message -> TestSuite +assertMessageIO s = makeTestSuite . Case s + +-- | All errors are turned into warnings +onlyWarnings :: TestSuite -> TestSuite +onlyWarnings = changeMessages $ \m -> + m { messageStatus = messageStatus m `min` Warning + , messageRating = mempty + } + +rateOnError :: Int -> TestSuite -> TestSuite +rateOnError n = changeMessages $ \m -> + if isError m then m { messageRating = Rating n } else m + +changeMessages :: (Message -> Message) -> TestSuite -> TestSuite +changeMessages f = changeTS + where + changeTS (TS xs) = TS (fmap changeTest xs) + changeTest (Case s io) = Case s (f <$> io) + changeTest (Suite s t) = Suite s (changeTS t) + +---------------------------------------------------------------- +-- Running a test suite + +runTestSuite :: Bool -> TestSuite -> IO () +runTestSuite chattyIO = void . runTestSuiteResult chattyIO + +runTestSuiteResult :: Bool -> TestSuite -> IO Result +runTestSuiteResult chattyIO ts = do + hSetBuffering stdout NoBuffering + ref <- newIORef 0 + result <- runner ref chattyIO ts + newline ref + return result + +runner :: IORef Int -> Bool -> TestSuite -> IO Result +runner ref chattyIO = runTS + where + runTS :: TestSuite -> IO Result + runTS ts = do + (res, dt) <- getDiffTime (foldM addTest mempty (tests ts)) + returnStrict res { diffTime = dt } + + runTest :: Test -> IO Result + runTest t = + case t of + Suite s xs -> runSuite s xs + Case s io -> runTestCase s io + + runSuite ::String -> TestSuite -> IO Result + runSuite s ts = do + when chattyIO $ do + newline ref + putStrLn s + reset ref + result <- runTS ts + returnStrict (suiteResult s result) + + runTestCase :: String -> IO Message -> IO Result + runTestCase s io = do + msg <- io `catch` handler + case messageStatus msg of + _ | not chattyIO -> return () + Ok -> dot ref + _ -> do + newlineIndent ref + print msg + reset ref + returnStrict (caseResult (s, msg)) + where + handler :: SomeException -> IO Message + handler = return . message . show + + addTest :: Result -> Test -> IO Result + addTest res t = (res <>) <$> runTest t + +-- formatting helpers +type WriteIO a = IORef Int -> IO a + +newline :: WriteIO () +newline ref = do + i <- readIORef ref + when (i>0) (putChar '\n') + reset ref + +newlineIndent :: WriteIO () +newlineIndent ref = do + newline ref + putStr " " + writeIORef ref 3 + +dot :: WriteIO () +dot ref = do + i <- readIORef ref + unless (i>0 && i<60) (newlineIndent ref) + putChar '.' + modifyIORef ref (+1) + +reset :: WriteIO () +reset = (`writeIORef` 0) + +---------------------------------------------------------------- +-- Test Suite Result + +data Result = Result + { suites :: S.Seq (String, Result) + , cases :: S.Seq (String, Message) + , diffTime :: !NominalDiffTime + , nrOfTests :: !Int + , nrOfWarnings :: !Int + , nrOfErrors :: !Int + , resultRating :: !Rating + } + +-- one-line summary +instance Show Result where + show result = + "(tests: " ++ show (nrOfTests result) ++ + ", errors: " ++ show (nrOfErrors result) ++ + ", warnings: " ++ show (nrOfWarnings result) ++ + ", " ++ show (diffTime result) ++ ")" + +instance Monoid Result where + mempty = Result mempty mempty 0 0 0 0 mempty + x `mappend` y = Result + { suites = suites x <> suites y + , cases = cases x <> cases y + , diffTime = diffTime x + diffTime y + , nrOfTests = nrOfTests x + nrOfTests y + , nrOfWarnings = nrOfWarnings x + nrOfWarnings y + , nrOfErrors = nrOfErrors x + nrOfErrors y + , resultRating = resultRating x <> resultRating y + } + +instance HasStatus Result where + getStatus r | nrOfErrors r > 0 = Error + | nrOfWarnings r > 0 = Warning + | otherwise = Ok + +instance HasRating Result where + rating = rating . resultRating + rate n a = a {resultRating = Rating n} + +suiteResult :: String -> Result -> Result +suiteResult s res = mempty + { suites = S.singleton (s, res) + , nrOfTests = nrOfTests res + , nrOfWarnings = nrOfWarnings res + , nrOfErrors = nrOfErrors res + , resultRating = resultRating res + } + +caseResult :: (String, Message) -> Result +caseResult x@(_, msg) = + case getStatus msg of + Ok -> new + Warning -> new { nrOfWarnings = 1 } + Error -> new { nrOfErrors = 1 } + where + new = mempty + { cases = S.singleton x + , nrOfTests = 1 + , resultRating = messageRating msg + } + +subResults :: Result -> [(String, Result)] +subResults = toList . suites + +topMessages :: Result -> [(String, Message)] +topMessages = toList . cases + +allMessages :: Result -> [(String, Message)] +allMessages res = + topMessages res ++ concatMap (allMessages . snd) (subResults res) + +findSubResult :: String -> Result -> Maybe Result +findSubResult name = listToMaybe . recs + where + recs = concatMap rec . subResults + rec (n, t) + | n == name = [t] + | otherwise = recs t + +justOneSuite :: Result -> Maybe (String, Result) +justOneSuite res = + case subResults res of + [x] | S.null (cases res) -> Just x + _ -> Nothing + +timeInterval :: Result -> Double +timeInterval = fromRational . toRational . diffTime + +printSummary :: Result -> IO () +printSummary = putStrLn . makeSummary + +makeSummary :: Result -> String +makeSummary result = unlines $ + [ line + , "Tests : " ++ show (nrOfTests result) + , "Errors : " ++ show (nrOfErrors result) + , "Warnings : " ++ show (nrOfWarnings result) + , "" + , "Time : " ++ show (diffTime result) + , "" + , "Suites: " + ] ++ map f (subResults result) + ++ [line] + where + line = replicate 75 '-' + f (name, r) = " " ++ name ++ " " ++ show r + +----------------------------------------------------- +-- Message + +data Message = M + { messageStatus :: !Status + , messageRating :: !Rating + , messageLines :: [String] + } + deriving Eq + +instance Show Message where + show a = st ++ sep ++ msg + where + msg = intercalate ", " (messageLines a) + sep = if null st || null msg then "" else ": " + st | isError a = "error" + | isWarning a = "warning" + | null (messageLines a) = "ok" + | otherwise = "" + +instance Monoid Message where + mempty = M mempty mempty mempty + M s r xs `mappend` M t q ys = M (s <> t) (r <> q) (xs <> ys) + +instance HasStatus Message where + getStatus = messageStatus + +instance HasRating Message where + rating = rating . messageRating + rate n a = a {messageRating = Rating n} + +message :: String -> Message +message = M Error (Rating 0) . return + +warning :: String -> Message +warning = M Warning mempty . return + +----------------------------------------------------- +-- Status + +data Status = Ok | Warning | Error + deriving (Eq, Ord) + +instance Monoid Status where + mempty = Ok + mappend = max + +class HasStatus a where + getStatus :: a -> Status + +isOk, isWarning, isError :: HasStatus a => a -> Bool +isOk = (== Ok) . getStatus +isWarning = (== Warning) . getStatus +isError = (== Error) . getStatus + +----------------------------------------------------- +-- Rating + +data Rating = Rating !Int | MaxRating + deriving (Eq, Ord) + +instance Monoid Rating where + mempty = MaxRating + mappend = min + +class HasRating a where + rating :: a -> Maybe Int + rate :: Int -> a -> a + +instance HasRating Rating where + rating (Rating n) = Just n + rating MaxRating = Nothing + rate = const . Rating + +----------------------------------------------------- +-- Utility function + +getDiffTime :: IO a -> IO (a, NominalDiffTime) +getDiffTime action = do + t0 <- getCurrentTime + a <- action + t1 <- getCurrentTime + return (a, diffUTCTime t1 t0) + +returnStrict :: Monad m => a -> m a +returnStrict a = a `seq` return a
+ src/Ideas/Utils/Typeable.hs view
@@ -0,0 +1,70 @@+{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TypeOperators #-} +{-# LANGUAGE TypeFamilies #-} +----------------------------------------------------------------------------- +-- Copyright 2016, Ideas project team. This file is distributed under the +-- terms of the Apache License 2.0. For more information, see the files +-- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution. +----------------------------------------------------------------------------- +-- | +-- Maintainer : bastiaan.heeren@ou.nl +-- Stability : provisional +-- Portability : portable (depends on ghc) +-- +-- Typeable type class, with the IsTypeable data type for witnessing instances +-- +----------------------------------------------------------------------------- + +module Ideas.Utils.Typeable + ( IsTypeable, typeable + , HasTypeable(..) + , castFrom, castTo, castBetween + , gcastFrom, gcastTo, gcastBetween + , module Data.Typeable + ) where + +import Control.Monad +import Data.Typeable +import Unsafe.Coerce + +newtype IsTypeable a = IT TypeRep + +class HasTypeable f where + getTypeable :: f a -> Maybe (IsTypeable a) + +instance HasTypeable IsTypeable where + getTypeable = Just + +typeable :: forall a . Typeable a => IsTypeable a +typeable = IT (typeRep (Proxy :: Proxy a)) + +castFrom :: (HasTypeable f, Typeable b) => f a -> a -> Maybe b +castFrom = flip castBetween typeable + +castTo :: (HasTypeable f, Typeable a) => f b -> a -> Maybe b +castTo = castBetween typeable + +castBetween :: (HasTypeable f, HasTypeable g) => f a -> g b -> a -> Maybe b +castBetween x y a = do + guardEq x y + return $ unsafeCoerce a + +gcastFrom :: (HasTypeable f, Typeable b) => f a -> c a -> Maybe (c b) +gcastFrom = flip gcastBetween typeable + +gcastTo :: (HasTypeable f, Typeable a) => f b -> c a -> Maybe (c b) +gcastTo = gcastBetween typeable + +gcastBetween :: (HasTypeable f, HasTypeable g) => f a -> g b -> c a -> Maybe (c b) +gcastBetween ta tb x = fmap (\Refl -> x) (eqIT ta tb) + +eqIT :: (HasTypeable f, HasTypeable g) => f a -> g b -> Maybe (a :~: b) +eqIT x y = do + guardEq x y + return $ unsafeCoerce Refl + +guardEq :: (HasTypeable f, HasTypeable g) => f a -> g b -> Maybe () +guardEq x y = do + IT ta <- getTypeable x + IT tb <- getTypeable y + guard (ta == tb)
+ src/Ideas/Utils/Uniplate.hs view
@@ -0,0 +1,25 @@+----------------------------------------------------------------------------- +-- Copyright 2016, Ideas project team. This file is distributed under the +-- terms of the Apache License 2.0. For more information, see the files +-- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution. +----------------------------------------------------------------------------- +-- | +-- Maintainer : bastiaan.heeren@ou.nl +-- Stability : provisional +-- Portability : portable (depends on ghc) +-- +-- Exports a subset of Data.Generics.Uniplate.Direct (the @Uniplate@ type +-- class and its utility plus constructor functions) +-- +----------------------------------------------------------------------------- + +module Ideas.Utils.Uniplate + ( -- * Uniplate type class and utility functions + Uniplate + , children, contexts, descend, descendM, holes, para + , rewrite, rewriteM, transform, transformM, uniplate, universe + -- * Instance constructors + , (|-), (|*), (||*), plate + ) where + +import Data.Generics.Uniplate.Direct