packages feed

liquidhaskell-0.7.0.0: tests/strings/pos/StringIndexingStep2.hs

{-# LANGUAGE KindSignatures      #-}
{-# LANGUAGE DataKinds           #-}
{-# LANGUAGE OverloadedStrings   #-}
{-# LANGUAGE RankNTypes          #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE GADTs               #-}


{-@ LIQUID "--totality"          @-}
{-@ LIQUID "--stringtheory"      @-}

module StringIndexing where


import GHC.TypeLits
import Data.String 

import Data.Proxy 
-- Structure that defines valid indeces of a type level target 
-- symbol in a value level string

data MI (tagret :: Symbol) s where 
  MI :: IsString s => s        -- input string
                   -> [Int]    -- valid indeces of target in input
                   -> MI target s

{-@ MI :: input:s 
       -> [GoodIndex input target]
       -> MI s @-}


{-@ type GoodIndex Input Target 
  = {i:Int |  IsGoodIndex Input Target i}
  @-}

{-@ predicate IsGoodIndex Input Target I
  =  (subString Input I (stringLen Target)  == Target)
  && (I + stringLen Target < stringLen Input)
  && (0 <= I)
  @-}

{-@ measure stringLen    :: String -> Int @-}
{-@ measure subString    :: String -> Int -> Int -> String @-}
{-@ measure concatString :: String -> String -> String @-}

mempty :: forall (target :: Symbol). MI target String
mempty = MI "" []


mappend :: forall (target :: Symbol). (KnownSymbol target) => MI target String -> MI target String -> MI target String
mappend (MI i1 is1) (MI i2 is2)
  = MI input (is ++ is1 ++ map ((length i1) +) is2)
  where 
    is     = filterIndex input target [(len1 - len) .. (len1 + len)]
    input  = i1 `concatString` i2 
    len1   = length i1 
    len    = length target 
    target = symbolVal (Proxy :: Proxy target)


{-@ symbolVal :: forall n proxy. KnownSymbol n => proxy n -> {v:String | v == n} @-}

filterIndex :: String -> String -> [Int] -> [Int]
{-@ filterIndex :: input:String -> target:String -> is:[Int] -> [GoodIndex input target] / [len is] @-}
filterIndex _ _ [] = []
filterIndex input target (i:is)
  | isGoodIndex input target i
  = i:filterIndex input target is 
  | otherwise 
  =   filterIndex input target is 


isGoodIndex :: String -> String -> Int -> Bool 
{-@ isGoodIndex :: input:String -> target:String -> i:Int 
  -> {b:Bool | Prop b <=> IsGoodIndex input target i} @-}
isGoodIndex input target i 
  =  subString input i (stringLen target)  == target  
  && i + stringLen target < stringLen input
  && 0 <= i

{-@ concatString :: x:String -> y:String -> {v:String | v == concatString x y && stringLen v == stringLen x + stringLen y } @-}
concatString :: String -> String -> String
concatString = undefined 

{-@ stringLen    :: s:String -> {v:Int | v == stringLen s} @-}
stringLen :: String -> Int 
stringLen = length 

{-@ subString  :: s:String -> offset:Int -> ln:Int -> {v:String |v == subString s offset ln } @-}
subString :: String -> Int -> Int -> String 
subString = undefined