def f(x, y):
return x & 1 == 0 and y > 0
g = lambda x, y: x & 1 == 0 and y > 0
Now the same thing in Haskell:
import Data.Bits
f :: Int -> Int -> Bool
f x y = (.&.) x 1 == 0 && y > 0
That works, however this doesn't:
g = \x y -> (.&.) x 1 == 0 && y > 0
Here's the error this gives:
someFunc :: IO ()
someFunc = putStrLn $ "f 5 7: " ++ ( show $ f 5 7 ) ++ "\tg 5 7: " ++ ( show $ g 5 7 )
• Ambiguous type variable ‘a0’ arising from the literal ‘1’
prevents the constraint ‘(Num a0)’ from being solved.
Relevant bindings include
x :: a0 (bound at src/Lib.hs:13:6)
g :: a0 -> Integer -> Bool (bound at src/Lib.hs:13:1)
Probable fix: use a type annotation to specify what ‘a0’ should be.
These potential instances exist:
instance Num Integer -- Defined in ‘GHC.Num’
instance Num Double -- Defined in ‘GHC.Float’
instance Num Float -- Defined in ‘GHC.Float’
...plus two others
...plus one instance involving out-of-scope types
(use -fprint-potential-instances to see them all)
• In the second argument of ‘(.&.)’, namely ‘1’
In the first argument of ‘(==)’, namely ‘(.&.) x 1’
In the first argument of ‘(&&)’, namely ‘(.&.) x 1 == 0’
|
13 | g = \x y -> (.&.) x 1 == 0 && y > 0
| ^
How do I get the same error in Python? - How do I get errors when the input doesn't match expectations?
To be specific, how do I say that a function/lambda MUST have:
__matmul__
(@
)bool
I know that I can roughly do this with: (docstrings and/or PEP484) with abc
; for classes. But what can I do for 'loose' functions in a module?
One trick I found was to use Callback Protocols:
from typing import Optional, Iterable
from sys import version_info
if version_info > (3, 8):
from typing import Protocol
else:
from typing_extensions import Protocol
class Combiner(Protocol):
def __call__(self, *vals: bytes, maxlen: Optional[int] = None) -> list[bytes]: ...
Applied to my problem, just duplicate:
def combiner0(*vals: bytes, maxlen: Optional[int] = None) -> list[bytes]: return []
def combiner1(*vals, maxlen = None): return []
# Unused var just for type checking
_combiner: Combiner = combiner0
_combiner: Combiner = combiner1
del _combiner