Маловідомий факт полягає в тому, що якщо увімкнути достатню кількість мовних розширень (ghc), Haskell стає динамічно набраною інтерпретованою мовою! Наприклад, наступна програма реалізує додавання.
{-# 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)
Це вже не схоже на Haskell. Для одного, а не для роботи над об'єктами, ми працюємо над типами. Кожне число - це власний тип. Замість функцій у нас є типи класів. Функціональні залежності дозволяють використовувати їх як функції між типами.
То як ми можемо викликати наш код? Ми використовуємо інший клас
class Test a | -> a
where test :: a
instance (Add (Succ (Succ (Succ (Succ Zero)))) (Succ (Succ (Succ Zero))) a)
=> Test a
Це встановлює тип test
до типу 4 + 3. Якщо ми відкриємо це в ghci, ми виявимо, що test
це дійсно типу 7:
Ok, one module loaded.
*Main> :t test
test :: Succ (Succ (Succ (Succ (Succ (Succ (Succ Zero))))))
Завдання
Я хочу, щоб ви реалізували клас, що множить дві цифри Пеано (невід'ємні цілі числа). Число Peano буде побудовано за допомогою тих самих типів даних у наведеному вище прикладі:
data Zero
data Succ a
І ваш клас буде оцінюватися так само, як і вище. Ви можете назвати свій клас, що завгодно.
Ви можете використовувати будь-які розширення мови ghc, які хочете, без байт.
Випробування
Ці тестові випадки передбачають, що ваш клас названий M
, ви можете назвати його чимось іншим, якщо хочете.
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
Результати
*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)))))))))))))))))
Черпає натхнення від набору технічного інтерв'ю