{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE NoStarIsType #-}
module Predicate.Examples.Common (
DateNip
, DateFmts
, DateTimeFmts
, DateTimeNip
, Dtip
, Dtfmt
, DdmmyyyyRE
, Ddmmyyyyop
, Ddmmyyyyop'
, JsonMicrosoftDateTime
, Hmsip
, Hmsop
, Hmsop'
, Hmsfmt
, HmsRE
, Luhnip
, Luhnop
, Luhnfmt
, Luhn'
, Luhnop'
, Ssnip
, Ssnop
, Ssnfmt
, Ip4ip
, Ip4ip'
, Ip4op
, Ip4op'
, Ip4fmt
, OctetRE
, Ip4RE
, Ip4StrictRE
, Ip6ip
, Ip6op
, Ip6fmt
, Isbn10ip
, Isbn10op
, Isbn10fmt
, Isbn13ip
, Isbn13op
, Isbn13fmt
) where
import Predicate.Prelude
import GHC.TypeLits (Nat)
import Data.Time (Day, UTCTime, ZonedTime)
type Luhnip = Map' (ReadP Int Id) (Remove "-" Id >> Ones)
type Luhnop (n :: Nat) = GuardBool (PrintT "expected %d digits but found %d" '(n,Len)) (Len == n) && GuardBool "invalid checkdigit" IsLuhn
type Luhnfmt (ns :: [Nat]) = ConcatMap (ShowP Id) Id >> SplitAts ns Id >> Intercalate '["-"] Id >> Concat
type Dtip t = ParseTimeP t "%F %T"
type Dtfmt = FormatTimeP "%F %T"
type Ssnip = Map' (ReadP Int Id) (Rescan "^(\\d{3})-(\\d{2})-(\\d{4})$" >> OneP >> Snd)
type Ssnop = BoolsQuick (PrintT "number for group %d invalid: found %d" Id)
'[Between 1 899 Id && Id /= 666, Between 1 99 Id, Between 1 9999 Id]
type Ssnfmt = PrintL 3 "%03d-%02d-%04d" Id
type Hmsip = Map' (ReadP Int Id) (Resplit ":")
type Hmsop = GuardsDetail "%s invalid: found %d" '[ '("hours", Between 0 23 Id),'("minutes",Between 0 59 Id),'("seconds",Between 0 59 Id)] >> 'True
type Hmsop' = Bools '[ '("hours", Between 0 23 Id), '("minutes",Between 0 59 Id), '("seconds",Between 0 59 Id) ]
type Hmsfmt = PrintL 3 "%02d:%02d:%02d" Id
type HmsRE = "^([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$"
type Ip4RE = "^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$"
type Ip4ip = Map' (ReadP Int Id) (Resplit "\\.")
type Ip4ip' = Map' (ReadP Int Id) (Rescan Ip4RE >> OneP >> Snd)
type Ip4op' = BoolsN (PrintT "octet %d out of range 0-255 found %d" Id) 4 (0 <..> 0xff)
type Ip4op = GuardsN 4 (PrintT "octet %d out of range 0-255 found %d" Id) (0 <..> 0xff) >> 'True
type Ip4fmt = PrintL 4 "%03d.%03d.%03d.%03d" Id
type OctetRE = "(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])"
type Ip4StrictRE = "^" <%> IntersperseT "\\." (RepeatT 4 OctetRE) <%> "$"
type Ip6ip = Resplit ":"
>> Map (If (Id == "") "0" Id)
>> Map (ReadBase Int 16)
>> PadL 8 0 Id
type Ip6op = Msg "count is bad:" (Len == 8)
&& Msg "out of bounds:" (All (0 <..> 0xffff))
type Ip6fmt = PrintL 8 "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x" Id
type Isbn10ip = Resplit "-"
>> Concat
>> 'Just Unsnoc
>> Map (ReadP Int (Singleton Id)) *** If (Singleton Id ==~ "X") 10 (ReadP Int (Singleton Id))
type Isbn10op = GuardSimple ((Fst >> All (0 <..> 9)) && Between 0 10 Snd)
>> ZipWith (Fst * Snd) (1...10 >> Reverse) (Fst +: Snd)
>> Sum
>> GuardBool "mod 0 oops" (Id `Mod` 11 == 0)
type Isbn10fmt = ConcatMap (ShowP Id) Id *** If (Id == 10) "X" (ShowP Id)
>> Fst <> "-" <> Snd
type Isbn13ip = Resplit "-"
>> Concat
>> Map (ReadP Int (Singleton Id))
type Isbn13op = ZipWith (Fst * Snd) (Cycle 13 [1,3] >> Reverse) Id
>> Sum
>> '(Id,Id `Mod` 10)
>> GuardBool (PrintT "sum=%d mod 10=%d" Id) (Snd == 0)
type Isbn13fmt = 'Just Unsnoc >> ConcatMap (ShowP Id) Fst <> "-" <> ShowP Snd
type DateFmts = '["%Y-%m-%d", "%m/%d/%y", "%B %d %Y"]
type DateNip = ParseTimes Day DateFmts Id
type DateTimeFmts = '["%Y-%m-%d %H:%M:%S", "%m/%d/%y %H:%M:%S", "%B %d %Y %H:%M:%S", "%Y-%m-%dT%H:%M:%S"]
type DateTimeNip = ParseTimes UTCTime DateTimeFmts Id
type DdmmyyyyRE = "^(\\d{2})-(\\d{2})-(\\d{4})$"
type Ddmmyyyyop = GuardsDetail "%s %d is out of range" '[ '("day", Between 1 31 Id), '("month", Between 1 12 Id), '("year", Between 1990 2050 Id) ] >> 'True
type Ddmmyyyyop' = Bools '[ '("day", Between 1 31 Id), '("month", Between 1 12 Id), '("year", Between 1990 2050 Id) ]
type Luhnop' (n :: Nat) =
Guard (PrintT "incorrect number of digits found %d but expected %d in [%s]" '(Len, n, ShowP Id)) (Len == n)
>> Do '[
Reverse
,ZipWith (Fst * Snd >> If (Id >= 10) (Id - 9) Id) (Cycle n [1,2]) Id
,Sum
]
>> Guard (PrintT "expected %d mod 10 = 0 but found %d" '(Id, Id `Mod` 10)) (Mod Id 10 == 0)
type Luhn' (n :: Nat) =
Msg "Luhn'" (Do
'[Guard (PrintT "incorrect length: found %d but expected %d in [%s]" '(Len, n, Id)) (Len == n)
,Do
'[Ones
,Map (ReadP Int Id)
,Reverse
,ZipWith (Fst * Snd >> If (Id >= 10) (Id - 9) Id) (Cycle n [1,2]) Id
,Sum
]
,Guard (PrintT "expected %d mod 10 = 0 but found %d" '(Id, Id `Mod` 10)) (Mod Id 10 == 0)
])
type JsonMicrosoftDateTime =
Do '[ Rescan "^Date\\(([-+])?(\\d*?)(\\d{0,3})([+-]\\d{4})\\)"
, Head
, Snd
, If (Id !! 0 == "-") "-" ""
<> PadL 1 (C "0") (Id !! 1)
<> "."
<> PadL 3 (C "0") (Id !! 2)
<> Id !! 3
, ParseTimeP ZonedTime "%s%Q%z"
]