91 lines
2.3 KiB
Python
91 lines
2.3 KiB
Python
'''Determine if a string has all the same characters'''
|
|
|
|
from itertools import takewhile
|
|
|
|
|
|
# inconsistentChar :: String -> Maybe (Int, Char)
|
|
def inconsistentChar(s):
|
|
'''Just the first inconsistent character and its position,
|
|
or Nothing if all the characters of s are the same,
|
|
'''
|
|
if s:
|
|
h = s[0]
|
|
pre, post = span(lambda c: h == c)(s)
|
|
return Just((len(pre), post[0])) if post else Nothing()
|
|
else:
|
|
return Nothing()
|
|
|
|
|
|
# --------------------------TEST---------------------------
|
|
# main :: IO ()
|
|
def main():
|
|
'''Consistency tests of seven strings'''
|
|
|
|
samples = ['', ' ', '2', '333', '.55', 'tttTTT', '4444 444']
|
|
w = 1 + max(map(len, samples))
|
|
|
|
def pfx(s):
|
|
return ("'" + s).rjust(w) + "' -> "
|
|
|
|
def charPosn(ic):
|
|
i, c = ic
|
|
return "inconsistent '" + c + "' (" + hex(ord(c)) + ")" + (
|
|
" at char " + str(1 + i)
|
|
)
|
|
|
|
print(main.__doc__ + ':\n')
|
|
print(
|
|
'\n'.join([
|
|
pfx(s) + maybe('consistent')(charPosn)(
|
|
inconsistentChar(s)
|
|
)
|
|
for s in samples
|
|
])
|
|
)
|
|
|
|
|
|
# -------------------------GENERIC-------------------------
|
|
|
|
# Just :: a -> Maybe a
|
|
def Just(x):
|
|
'''Constructor for an inhabited Maybe (option type) value.
|
|
Wrapper containing the result of a computation.
|
|
'''
|
|
return {'type': 'Maybe', 'Nothing': False, 'Just': x}
|
|
|
|
|
|
# Nothing :: Maybe a
|
|
def Nothing():
|
|
'''Constructor for an empty Maybe (option type) value.
|
|
Empty wrapper returned where a computation is not possible.
|
|
'''
|
|
return {'type': 'Maybe', 'Nothing': True}
|
|
|
|
|
|
# maybe :: b -> (a -> b) -> Maybe a -> b
|
|
def maybe(v):
|
|
'''Either the default value v, if m is Nothing,
|
|
or the application of f to x,
|
|
where m is Just(x).
|
|
'''
|
|
return lambda f: lambda m: v if None is m or m.get('Nothing') else (
|
|
f(m.get('Just'))
|
|
)
|
|
|
|
|
|
# span :: (a -> Bool) -> [a] -> ([a], [a])
|
|
def span(p):
|
|
'''The longest (possibly empty) prefix of xs
|
|
that contains only elements satisfying p,
|
|
tupled with the remainder of xs.
|
|
span p xs is equivalent to (takeWhile p xs, dropWhile p xs).
|
|
'''
|
|
def go(xs):
|
|
prefix = list(takewhile(p, xs))
|
|
return (prefix, xs[len(prefix):])
|
|
return lambda xs: go(xs)
|
|
|
|
|
|
# MAIN ---
|
|
if __name__ == '__main__':
|
|
main()
|