一个鲜为人知的事实是,如果您打开足够多的语言扩展(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数字(非负整数)相乘的类。在上面的示例中,将使用相同的数据类型构造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)))))))))))))))))
从打字技术采访中汲取灵感
语言扩展免费吗?如果是这样的话?
—
Potato44 '18年
@ Potato44哦,是的。所有语言扩展都是免费的。
—
Ad Hoc Garf Hunter,
嘿...尽管不是,但这篇帖子似乎很模因。
—
魔术章鱼缸