RosettaCodeData/Task/Determine-if-a-string-has-all-the-same-characters/Python/determine-if-a-string-has-all-the-same-characters-2.py
2023-07-01 13:44:08 -04:00

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()