digits = datasets.load_digits()
n_samples = len(digits.images)
X = digits.images.reshape((n_samples, -1))
y = digits.target
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.5, random_state=0)
tuned_parameters = [{'kernel': ['rbf'], 'gamma': [1e-3, 1e-4],
'C': [1, 10, 100, 1000]},
{'kernel': ['linear'], 'C': [1, 10, 100, 1000]}]
scores = ['precision', 'recall']
for score in scores:
clf = GridSearchCV(SVC(), tuned_parameters, cv=5, scoring='%s_macro' % score)
clf.fit(X_train, y_train)
print("Best parameters set found on development set:", clf.best_params_)
means = clf.cv_results_['mean_test_score']
stds = clf.cv_results_['std_test_score'],
for mean, std, params in zip(means, stds, clf.cv_results_['params']):
print("%0.3f (+/-%0.03f) for %r" % (mean, std * 2, params))
y_true, y_pred = y_test, clf.predict(X_test)
print(classification_report(y_true, y_pred))The simplified version of Parity Wallet Hack 1 is as follows:
The Wallet contract is a simple contract that uses delegatecall to execute transactions using WalletLibrary ’s code within the context of the Wallet function. The WalletLibrary contract assumes that it will be called in the context of a contract that does have state that it can modify (namely m_numOwners) and this is the core assumption that caused the recent disaster. In the first Parity Wallet Hack, the hacker changed the state of various Wallet contracts by delegating a call to initWallet, setting themselves as the owner of the Wallet contract and then withdrawing funds normally.
154 miliony dolarów...
The WalletLibrary contract assumes that it will be called in the context of a contract that does have state that it can modify (namely m_numOwners) and this is the core assumption that caused the recent disaster.
154 miliony dolarów...
Pozwalają nam:
Definicja:
foo :: Int -> Int
foo x = x + 10
bar :: String -> Int
bar s = length sWywołanie:
foo 42
bar "Haskell is love, haskell is life"Definicja:
data Foo = Foo Int | Bar StringStworzenie wartości:
foo = Foo 42
bar = Bar "Haskell"Użycie w funkcji:
someFun :: Foo -> Foo
someFun (Foo x) = Foo (x + 1)
someFun (Bar s) = Bar (s ++ s)Definicja:
newtype Dollar = Dollar DoubleStworzenie wartości:
amountUsd = Dollar 123.0Użycie w funkcji:
someFun :: Dollar -> Dollar
someFun (Dollar amt) = Dollar $ amt + 10.0Let:
let x = 15 in x + 10
foo :: Int -> Foo
foo x =
let s = show (x + 100)
in Bar sWhere:
x + 10 where x = 15
foo :: Int -> Foo
foo x = Bar s
where s = show (x + 100)Funkcje bez nazwy:
\x -> x + 1
\x y -> x + yUżycie:
filter (\x -> x `mod` 2 == 1) [1,2,3,4,5]
map (\x -> x + 10) [1,2,3,4,5] -- map (+ 10) [1,2,3,4,5]Prawdziwy, parametryczny!
foo :: a -> [a]
foo x = [x, x, x]
map :: (a -> b) -> [a] -> [b]
map f [] = []
map f (x:xs) = f x : map f xs
(.) :: (b -> c) -> (a -> b) -> a -> c
(.) f g x = f (g x)Typy danych:
data Foo a b = Foo a | Bar bFunkcje:
Dolar (aplikacja funkcji):
f (g x)
-- to to samo, co:
f $ g xBezpunktowość:
f x = g x
-- to to samo, co
f = g
-- natomiast:
foo x = f $ g x
-- to to samo, co:
foo = f . gDefinicja:
class Addable a where
add :: a -> a -> a
zero :: aInstancja:
reduce :: Addable a => [a] -> a
reduce = foldl add zeroWykorzystanie w funkcji:
instance Addable Foo where
add (Foo x) (Foo y) = Foo $ x + y
add (Foo x) (Bar s) = Bar $ show x <> s
add (Bar s) (Bar z) = Bar $ s <> z
zero = Foo 0Ulepszmy nieco naszą typeclassę!
class Addable a b where
type Res a b
add :: a -> b -> Res a bInstancja:
data Foo = Foo Int
data Bar = Bar String
instance Addable Foo Bar where
type Res Foo Bar = Bar
add (Foo x) (Bar s) = Bar $ show x <> s
instance Addable Bar Foo where
type Res Bar Foo = Bar
add f b = add b f
instance Addable Foo Foo where
type Res Foo Foo = Foo
add (Foo x) (Foo y) = Foo $ x + y
instance Addable Bar Bar where
type Res Bar Bar = Bar
add (Bar s) (Bar z) = Bar $ s <> zPotrzebny tylko jeden tutorial:
W dużym skrócie:
someFunc :: Int -> IO Int
someFunc x = do
let y = x + 10
line <- getLine
pure $ y + length line
f :: Int -> Int
f <$> someFunc 10
g :: IO Int
g >>= someFunc
h :: Int -> IO Int
h >=> someFuncKojarzycie identyczność?
id :: forall a. a -> a
id a = aTaką funkcję można przekazać jako parametr:
poly id. -- działa!
poly (\n -> n + 1) -- nie działa! za mało polimorficzna!I wtedy musimy podać prawdziwie polimorficzną funkcję:
poly :: (forall a. a -> a) -> Bool
poly f = (f 0 < 1) == f trueptr :: Ptr Int <- mallocDa się ładniej?
sizeOf :: Storable a => a -> Int
sizeOf (undefined :: Int) --- bardzo brzydko!Przyjrzyjmy się bliżej. Weźmy sizeOf:
ptr <- malloc @IntZaalokujmy sobie pamięć:
sizeOf' :: forall a. Storable a => a -> Int
sizeOf' = sizeOf (undefined :: @a)
sizeOf' @Int -- dużo lepiej!Naprawmy to.
There's no such thing as a strongly typed language
M. Snoyman
data BankState = BankState
{ transactions :: [(String, String, Double)]
, conversionRates :: Map (String, String) Double
} deriving Show
wireMoney :: String -> String -> Double -> String -> BankState -> BankState
wireMoney fromAddr toAddr amount currency oldState = newState
where transaction = (fromAddr, toAddr, amountUSD)
transactions' = transaction : transactions oldState
conversionRates' = conversionRates oldState
amountUSD = convert currency "USD" amount oldState
newState = BankState transactions' conversionRates'Problem 1: nie o takiego Haskella walczyłem.
Rozwiązanie: użyjmy Lensów.
data BankState = BankState
{ _transactions :: [(String, String, Double)]
, _conversionRates :: Map (String, String) Double
} deriving Show
makeLenses ''BankState
wireMoney :: String -> String -> Double -> String -> BankState -> BankState
wireMoney fromAddr toAddr amount currency oldState =
oldState & transactions %~ (transaction :)
where transaction = (fromAddr, toAddr, amountUSD)
amountUSD = convert currency "USD" amount oldStateProblem 2: to nie jest type safe.
Rozwiązanie: użyjmy newtype'ów!
newtype FromAddr = FromAddr String deriving Show
newtype ToAddr = ToAddr String deriving Show
data BankState = BankState
{ _transactions :: [(FromAddr, ToAddr, Double)]
, _conversionRates :: Map (String, String) Double
} deriving Show
makeLenses ''BankState
wireMoney :: FromAddr -> ToAddr -> Double -> String -> BankState -> BankState
wireMoney fromAddr toAddr amount currency oldState =
oldState & transactions %~ (transaction :)
where transaction = (fromAddr, toAddr, amountUSD)
amountUSD = convert currency "USD" amount oldStateProblem 3: konwersja walut dalej nie jest type safe.
Rozwiązanie: użyjmy typeclass!
Lepiej! Nie pomylimy nadawcy z odbiorcą.
convert :: String -> String -> Double -> BankState -> Double
convert fromCurr toCurr amount bankState = rate * amount
where rates = bankState ^. conversionRates
rate = rates ! (fromCurr, toCurr)NAJ-GO-RZEJ.
Co się dzieje, gdy danej pary walut nie ma w mapie?
newtype Dollar = Dollar Double deriving Show
newtype Zloty = Zloty Double deriving Show
class Convertible a b | a -> b where
convert :: a -> b
instance Convertible Dollar Zloty where
convert (Dollar d) = Zloty $ d * 3.64
instance Convertible Zloty Dollar where
convert (Zloty z) = Dollar $ z * 0.27Teraz konwersje są definiowane statycznie, nie będzie błędu w runtime'ie.
data BankState = BankState
{ _transactions :: [(FromAddr, ToAddr, Dollar)]
} deriving Show
makeLenses ''BankState
wireMoney :: Convertible a Dollar
=> FromAddr -> ToAddr -> a -> BankState -> BankState
wireMoney fromAddr toAddr amount = transactions %~ (transaction :)
where transaction = (fromAddr, toAddr, amountUSD)
amountUSD = convert amountI tutaj już wygląda to dużo lepiej.
Jeszcze kosmetyka.
data Transaction a = Transaction
{ _fromAddr :: FromAddr
, _toAddr :: ToAddr
, _amount :: a
} deriving Show
makeLenses ''Transaction
newtype Ledger = Ledger
{ _transactions :: [Transaction Dollar]
} deriving Show
makeLenses ''Ledger
type BankState a = StateT Ledger IO a
emptyState :: Ledger
emptyState = Ledger []
wireMoney :: (Convertible a Dollar, MonadState Ledger m, MonadIO m)
=> Transaction a -> m ()
wireMoney t = do
let t' = t & amount %~ convert
State.modify $ transactions %~ (t' :)
runBank :: BankState () -> IO Ledger
runBank = flip State.execStateT emptyStateBank5.runBank $ do
let from = Bank5.FromAddr "from"
to = Bank5.ToAddr "to"
trans = Bank5.Transaction from to (Bank5.Zloty 123.0)
Bank5.wireMoney transŁadnie?