Haskell中简单的依赖类型的温度转换器,是否可以缩短此代码?
下面的函数Haskell中简单的依赖类型的温度转换器,是否可以缩短此代码?,haskell,dependent-type,idris,Haskell,Dependent Type,Idris,下面的函数convert具有类型签名: SUnit fromUnit->SUnit toUnit->Value fromUnit->Value toUnit 具有冗余,因为相同的信息可以通过以下方式表示: 单位值->单位值 1) 有没有办法去掉前两个参数(sunitfromUnit->sunittoUnit) 2) 有没有其他方法可以让这个简单的依赖类型的程序编写得更优雅 3) 这个程序在Idris中会是什么样子 {-# LANGUAGE GADTs,DataKinds,KindSignatur
convert
具有类型签名:
SUnit fromUnit->SUnit toUnit->Value fromUnit->Value toUnit
具有冗余,因为相同的信息可以通过以下方式表示:
单位值->单位值
1) 有没有办法去掉前两个参数(sunitfromUnit->sunittoUnit
)
2) 有没有其他方法可以让这个简单的依赖类型的程序编写得更优雅
3) 这个程序在Idris中会是什么样子
{-# LANGUAGE GADTs,DataKinds,KindSignatures #-}
main=do
putStrLn "Hello !"
-- putStrLn $ show $ convert SCelsius SCelsius kelvinZero -- this line does not compile
putStrLn $ show $ convert SKelvin SKelvin kelvinZero -- prints Value 0.0
putStrLn $ show $ convert SKelvin SCelsius kelvinZero -- prints Value (-273.16)
newtype Value (unit::Unit) = Value Double deriving Show
data Unit = Celsius | Kelvin
data SUnit u where
SCelsius:: SUnit Celsius
SKelvin:: SUnit Kelvin
offset=273.16
convert :: SUnit fromUnit-> SUnit toUnit ->Value fromUnit -> Value toUnit
convert SCelsius SKelvin (Value tempCel) = Value $tempCel+offset
convert SCelsius SCelsius (Value tempCel) = Value $tempCel
convert SKelvin SCelsius (Value tempK) = Value $tempK-offset
convert SKelvin SKelvin (Value tempK) = Value $tempK
kelvinZero::(Value 'Kelvin)
kelvinZero= Value 0
如果要删除前两个参数,在Haskell中需要一个typeclass
class IsUnit a where
getSUnit :: SUnit a
instance IsUnit Celsius where getSUnit = SCelsius
instance IsUnit Kelvin where getSUnit = SKelvin
convertShort :: (IsUnit fromUnit, IsUnit toUnit) => Value fromUnit -> Value toUnit
convertShort = convert getSUnit getSUnit
请注意,这使代码更长,而不是更短——但它允许调用方省略第一个单例值
上述代码还假设每个单元都可以转换为任何其他单元,这是不现实的。原始代码也包含此问题。如果不需要,可以使用两个参数类型的类:
class C from to where convert :: Value from -> Value to
instance C Kelvin Celsius where ...
-- etc.
如果要删除前两个参数,在Haskell中需要一个typeclass
class IsUnit a where
getSUnit :: SUnit a
instance IsUnit Celsius where getSUnit = SCelsius
instance IsUnit Kelvin where getSUnit = SKelvin
convertShort :: (IsUnit fromUnit, IsUnit toUnit) => Value fromUnit -> Value toUnit
convertShort = convert getSUnit getSUnit
请注意,这使代码更长,而不是更短——但它允许调用方省略第一个单例值
上述代码还假设每个单元都可以转换为任何其他单元,这是不现实的。原始代码也包含此问题。如果不需要,可以使用两个参数类型的类:
class C from to where convert :: Value from -> Value to
instance C Kelvin Celsius where ...
-- etc.
Ps,对于那些想知道如何在Idris中编写的人,Idris手册第3.4.3章“在函数中使用隐式参数”似乎是答案所在。Ps,对于那些想知道如何在Idris中编写的人,Idris手册第3.4.3章“在函数中使用隐式参数”似乎是答案所在。这很有用,因为它简化了调用方代码。这很有用,因为它简化了调用方代码。