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 testal 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