Ruby有一个很好的功能,允许将数字转换为其他东西,例如3.times迭代或3.to_s将其转换为字符串.
人们说Haskell很适合编写自然DSL.
是否可以将单位作为后缀来编写,例如timeout = 3 seconds?
nh2*_*nh2 74
是.
您可以使用以下简单方法执行此操作:
{-# LANGUAGE FlexibleInstances #-}
instance Num (Integer -> Integer) where
fromInteger n = \scale -> n * scale -- return a function that takes
-- a number and returns a number
Run Code Online (Sandbox Code Playgroud)
然后你可以写:
seconds, minutes, hours, days :: Integer
seconds = 1000000 -- base unit, e.g. microseconds
minutes = 60 seconds
hours = 60 minutes
days = 24 hours
soon :: Integer
soon = 2 hours + 4 seconds
Run Code Online (Sandbox Code Playgroud)
这是如何运作的?
上面我们给出了一个Num实例Integer -> Integer,即一个取整数并返回一个整数的函数.
实现Num并fromInteger定义其函数的每个类型都允许用数字文字表示,例如3.
这意味着我们可以编写3 :: Integer -> Integer- 这3是一个采用整数并返回整数的函数!
因此,我们可以对它应用整数,例如seconds; 我们可以写3 seconds,表达式将是类型Integer.
更安全的版本
事实上,我们3 (3 :: Integer)现在甚至可以写作- 尽管这可能没什么意义.我们可以通过使其更加类型安全来限制它:
newtype TimeUnit = TimeUnit Integer
deriving (Eq, Show, Num)
instance Num (TimeUnit -> TimeUnit) where
fromInteger n = \(TimeUnit scale) -> TimeUnit (n * scale)
seconds, minutes, hours, days :: TimeUnit
seconds = TimeUnit 1000000
minutes = 60 seconds
hours = 60 minutes
days = 24 hours
Run Code Online (Sandbox Code Playgroud)
现在我们只能将类型的东西TimeUnit应用于数字文字.
你可以为各种其他单位做到这一点,比如重量或距离或人.