def f(u, d, t, m):
return do_something(u, d, t, m, o)
def f(u, d, t, m):
return do_something(u, d, t, m, o)
def send_default_email(user, domain, topic, msg):
return send_email(user,
domain,
topic,
msg,
default_options)
def send_default_email(user: str, domain: str, topic: str, msg: str) -> str:
"""
Sends an email to 'user@domain'
>>> response = send_default_email('joe', 'computer.com', 'ur PR', 'lgtm')
>>> print(response)
>>> 'Email successful'
:param user: ...
:param domain: ...
:param msg: ...
:return: ...
"""
return send_email(user, domain, topic, msg, default_options)
tv_members = ['heneli']
responses = ['Success', 'Fail']
@precondition("user in tv_members")
@precondition("domain == tv.com")
@return(resp: str in responses)
def send_tv_email(user: str, domain: str, topic: str, msg: str) -> str:
"""
Sends an email to 'user@domain'
>>> response = send_tv_email('bob', 'tv.com', 'ur PR', 'lgtm')
*** Exception: User not in tv_members
>>> response = send_tv_email('heneli', 'tv.com', 'ur PR', 'lgtm')
'Success'
:param user: ...
:param domain: ...
:param msg: ...
:return: ...
"""
return send_email(user, domain, topic, msg, default_options)
head' :: [a] -> a
head' = \case
(x:_) -> x
[] -> error "empty list!"
endpts :: [Int] -> (Int, Int)
endpts [] = error "empty list!"
endpts xs = (head' xs, head' $ reverse xs)
endptsEx :: IO (Int, Int)
endptsEx = do
putStrLn "Enter a non-empty list of integers:"
xs <- readLn :: IO [Int]
if xs /= []
then pure (head' xs, head' $ reverse xs)
else endptsEx
Run-time failure on bad inputs
Returning a dummy value
* Everything can now be null or None
* All functions are responsible for checking for dummy value
headMay :: [a] -> Maybe a
headMay xs =
case xs of
(x:_) -> Just x
[] -> Nothing
safeEndpts :: [Int] -> Maybe (Int, Int)
safeEndpts xs =
case headMay xs of
Nothing -> Nothing
Just front ->
case reverse $ headMay xs of
Nothing -> Nothing
Just back -> Just (front, back)
Use an Optional Value
headMay :: [a] -> Maybe a
headMay xs =
case xs of
(x:_) -> Just x
[] -> Nothing
safeEndpts :: [Int] -> Maybe (Int, Int)
safeEndpts xs =
case headMay xs of
Nothing -> Nothing
Just x -> Just
( fromJust $ headMay xs
, fromJust . headMay $ reverse xs
)
Optional + Unsafe
* We already know the list is nonempty since headMay xs succeeded
fn :: String -> String -> String -> String -> IO String
fn u d t m = fn2 u d t m o
sendTVEmail :: String -> String -> String -> String -> IO String
sendTVEmail u d t m = sendEmail u d t m o
newtype EmailUser = EmailUser String
newtype EmailDomain = EmailDomain String
newtype EmailTopic = EmailTopic String
newtype EmailMessage = EmailMessage String
newtype EmailResponse = EmailResponse String
sendTVEmail :: EmailUser -> EmailDomain -> EmailTopic
-> EmailMessage -> IO EmailResponse
sendTVEmail usr domain topic msg =
sendEmail usr domain topic msg defaultOptions
nonEmptyUpToNPrintableAscii :: Int -> Gen Text
nonEmptyUpToNPrintableAscii n =
map pack . resize n
. listOf1
. suchThat arbitrary
$ ((&&) <$> isPrint <*> isAscii)
upToNPrintableAscii :: Int -> Gen Text
upToNPrintableAscii n =
map pack . resize n
. listOf
. suchThat arbitrary
$ ((&&) <$> isPrint <*> isAscii)
* Newtypes over base types (ex. Text)
* Ample documentation
* Manual checks where used or unsafe
* Tests that generate arbitrary values with some constraints
Define a “contract” using the @contract decorator:
from contracts import contract
@contract(x='int,>=0')
def f(x):
pass
>>> f(-2)
ContractNotRespected: Breach for argument 'x' to f().
Condition -2 >= 0 not respected
checking: >=0 for value: Instance of int: -2
checking: int,>=0 for value: Instance of int: -2
Define a “contract” using the @contract decorator:
Constraints on input
Use the “returns” keyword for constraints on the return value.
from contracts import contract
@contract(returns='int,>=0')
def f(x):
return x
Decorator argument
@contract
def f(x):
"""
Function description.
:type x: int,>0
:rtype: <=1
"""
@contract
def f(x:'int,>=0') -> '>=1':
...
@contract(x='int,>=0', returns='>=1')
def f(x):
...
Docstring
Python 3 Annotations
{-@ head :: { xs : [a] | 1 <= len xs } -> a @-}
head :: [a] -> a
head (x:_) = x
{-@ abs :: Int -> { n : Int | 0 <= n } @-}
abs :: Int -> Int
abs x = if x < 0 then 0 - x else x