Un fatto poco noto è che se si attivano abbastanza estensioni di linguaggio (ghc) Haskell diventa un linguaggio interpretato digitato dinamicamente! Ad esempio il seguente programma implementa l'aggiunta.
{-# Language MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, UndecidableInstances #-}
data Zero
data Succ a
class Add a b c | a b -> c
instance Add Zero a a
instance (Add a b c) => Add (Succ a) b (Succ c)
Non sembra più Haskell. Per uno invece di operare su oggetti, operiamo su tipi. Ogni numero è il proprio tipo. Invece delle funzioni abbiamo classi di tipi. Le dipendenze funzionali ci consentono di usarle come funzioni tra i tipi.
Quindi, come possiamo invocare il nostro codice? Usiamo un'altra classe
class Test a | -> a
where test :: a
instance (Add (Succ (Succ (Succ (Succ Zero)))) (Succ (Succ (Succ Zero))) a)
=> Test a
Questo imposta il tipo di test
al tipo 4 + 3. Se lo apriamo in ghci scopriremo che test
è effettivamente di tipo 7:
Ok, one module loaded.
*Main> :t test
test :: Succ (Succ (Succ (Succ (Succ (Succ (Succ Zero))))))
Compito
Voglio che tu implementi una classe che moltiplica due numeri Peano (numeri interi non negativi). I numeri di Peano saranno costruiti usando gli stessi tipi di dati nell'esempio sopra:
data Zero
data Succ a
E la tua classe verrà valutata allo stesso modo di cui sopra. Puoi nominare la tua classe come preferisci.
È possibile utilizzare qualsiasi estensione ghc desiderata per byte senza alcun costo.
Casi test
Questi casi di test presuppongono che la tua classe sia nominata M
, puoi nominarla in altro modo, se lo desideri.
class Test1 a| ->a where test1::a
instance (M (Succ (Succ (Succ (Succ Zero)))) (Succ (Succ (Succ Zero))) a)=>Test1 a
class Test2 a| ->a where test2::a
instance (M Zero (Succ (Succ Zero)) a)=>Test2 a
class Test3 a| ->a where test3::a
instance (M (Succ (Succ (Succ (Succ Zero)))) (Succ Zero) a)=>Test3 a
class Test4 a| ->a where test4::a
instance (M (Succ (Succ (Succ (Succ (Succ (Succ Zero)))))) (Succ (Succ (Succ Zero))) a)=>Test4 a
risultati
*Main> :t test1
test1
:: Succ
(Succ
(Succ
(Succ
(Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ Zero)))))))))))
*Main> :t test2
test2 :: Zero
*Main> :t test3
test3 :: Succ (Succ (Succ (Succ Zero)))
*Main> :t test4
test4
:: Succ
(Succ
(Succ
(Succ
(Succ
(Succ
(Succ
(Succ
(Succ
(Succ
(Succ
(Succ (Succ (Succ (Succ (Succ (Succ (Succ Zero)))))))))))))))))
Trae ispirazione dalla Digitazione dell'intervista tecnica