File: Perm.hs

package info (click to toggle)
haskell-syb 0.7.2.4-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 360 kB
  • sloc: haskell: 2,264; makefile: 2
file content (141 lines) | stat: -rw-r--r-- 4,460 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
{-# LANGUAGE DeriveDataTypeable  #-}
{-# LANGUAGE RankNTypes          #-}
{-# LANGUAGE ScopedTypeVariables #-}

module Perm (tests) where

{-

This module illustrates permutation phrases.
Disclaimer: this is a perhaps naive, certainly undebugged example.

-}

import Test.Tasty.HUnit

import Control.Applicative (Alternative(..), Applicative(..))
import Control.Monad
import Data.Generics

---------------------------------------------------------------------------
-- We want to read terms of type T3 regardless of the order T1 and T2.
---------------------------------------------------------------------------

data T1 = T1       deriving (Show, Eq, Typeable, Data)
data T2 = T2       deriving (Show, Eq, Typeable, Data)
data T3 = T3 T1 T2 deriving (Show, Eq, Typeable, Data)


---------------------------------------------------------------------------
-- A silly monad that we use to read lists of constructor strings.
---------------------------------------------------------------------------

-- Type constructor
newtype ReadT a = ReadT { unReadT :: [String] -> Maybe ([String],a) }



-- Run a computation
runReadT x y = case unReadT x y of
                 Just ([],y) -> Just y
                 _           -> Nothing

-- Read one string
readT :: ReadT String
readT =  ReadT (\x -> if null x
                        then Nothing
                        else Just (tail x, head x)
               )

instance Functor ReadT where
  fmap  = liftM

instance Applicative ReadT where
  pure x = ReadT (\y -> Just (y,x))
  (<*>) = ap

instance Alternative ReadT where
  (<|>) = mplus
  empty = mzero

-- ReadT is a monad!
instance Monad ReadT where
  return   = pure
  c >>= f  = ReadT (\x -> case unReadT c x of
                            Nothing -> Nothing
                            Just (x', a) -> unReadT (f a) x'
                   )

-- ReadT also accommodates mzero and mplus!
instance MonadPlus ReadT where
  mzero = ReadT (const Nothing)
  f `mplus` g = ReadT (\x -> case unReadT f x of
                               Nothing -> unReadT g x
                               y -> y
                      )


---------------------------------------------------------------------------
-- A helper type to appeal to predicative type system.
---------------------------------------------------------------------------

newtype GenM = GenM { unGenM :: forall a. Data a => a -> ReadT a }


---------------------------------------------------------------------------
-- The function that reads and copes with all permutations.
---------------------------------------------------------------------------

buildT :: forall a. Data a => ReadT a
buildT = result

 where
  result = do str <- readT
              con <- string2constr str
              ske <- return $ fromConstr con
              fs  <- return $ gmapQ buildT' ske
              perm [] fs ske

  -- Determine type of data to be constructed
  myType = myTypeOf result
    where
      myTypeOf :: forall a. ReadT a -> a
      myTypeOf =  undefined

  -- Turn string into constructor
  string2constr str = maybe mzero
                            return
                            (readConstr (dataTypeOf myType) str)

  -- Specialise buildT per kid type
  buildT' :: forall a. Data a => a -> GenM
  buildT' (_::a) = GenM (const mzero `extM` const (buildT::ReadT a))

  -- The permutation exploration function
  perm :: forall a. Data a => [GenM] -> [GenM] -> a -> ReadT a
  perm [] [] a = return a
  perm fs [] a = perm [] fs a
  perm fs (f:fs') a = (
                        do a' <- gmapMo (unGenM f) a
                           perm fs fs' a'
                      )
                        `mplus`
                      (
                        do guard (not (null fs'))
                           perm (f:fs) fs' a
                      )


---------------------------------------------------------------------------
-- The main function for testing
---------------------------------------------------------------------------

tests =
     ( runReadT buildT ["T1"] :: Maybe T1           -- should parse fine
   , ( runReadT buildT ["T2"] :: Maybe T2           -- should parse fine
   , ( runReadT buildT ["T3","T1","T2"] :: Maybe T3 -- should parse fine
   , ( runReadT buildT ["T3","T2","T1"] :: Maybe T3 -- should parse fine
   , ( runReadT buildT ["T3","T2","T2"] :: Maybe T3 -- should fail
   ))))) @=? output

output = (Just T1,(Just T2,(Just (T3 T1 T2),(Just (T3 T1 T2),Nothing))))