在Haskell中,如何强制表达式为函数的返回类型?

时间:2014-09-09 22:32:05

标签: haskell types integer polymorphism

我想将此函数概括为(Integral a, Integral b, Bounded b) => a -> [b],但我不知道如何强制maxBound获得结果的类型。这可能吗?

go :: Integral a => a -> Maybe (Word8, a)
go 0 = Nothing
go x 
    | x < 0 = error "Negative numbers are not acceptable"
    | otherwise = Just $ (remainder, quotient)
    where
        quotient = fromInteger $ (toInteger x) `div` (toInteger (maxBound :: Word8))
        remainder = fromInteger $ (toInteger x) `mod` (toInteger (maxBound :: Word8))

int2WordList :: Integral a => a -> [Word8]
int2WordList x = unfoldr go x

2 个答案:

答案 0 :(得分:5)

基本上,您希望在函数中的某个位置使用类型参数。这正是scoped type variables的用途:

{-# LANGUAGE ScopedTypeVariables #-}
import Data.Word
import Data.List

go :: forall a b. (Integral a, Integral b, Bounded b) => a -> Maybe (b, a)
go 0 = Nothing
go x 
    | x < 0 = error "Negative numbers are not acceptable"
    | otherwise = Just $ (remainder, quotient)
    where
        quotient  = fromInteger $ (toInteger x) `div` (toInteger (maxBound :: b))
        remainder = fromInteger $ (toInteger x) `mod` (toInteger (maxBound :: b))
    --                                                                        ^
    --                                               that's the same `b` as above   

int2List :: (Integral a, Integral b, Bounded b) => a -> [b]
int2List x = unfoldr go x

或者,您可以使用asTypeOf

go :: (Integral a, Integral b, Bounded b) => a -> Maybe (b, a)
go 0 = Nothing
go x 
    | x < 0 = error "Negative numbers are not acceptable"
    | otherwise = Just $ (remainder, quotient)
    where
        quotient  = fromInteger $ (toInteger x) `div` (toInteger (maxBound `asTypeOf` remainder))
        remainder = fromInteger $ (toInteger x) `mod` (toInteger (maxBound `asTypeOf` remainder))

int2List :: (Integral a, Integral b, Bounded b) => a -> [b]
int2List x = unfoldr go x

asTypeOf是一个相当简单的函数,但其​​类型确保remaindermaxBound具有相同的类型:

asTypeOf :: a -> a -> a
asTypeOf = const

答案 1 :(得分:3)

Haskell 98解决此问题的方法是asTypeOf函数,例如:

quotient  = fromInteger $ (toInteger x) `div` (toInteger (maxBound `asTypeOf` remainder))

我建议稍微重新处理你的表达式:

xInt = toInteger x
mbound = toInteger (maxBound `asTypeOf` remainder)
quotient = fromInteger $ xInt `div` mbound
remainder = fromInteger $ xInt `div` mbound

这将使您更清楚地想要将x除以相同的值,然后将结果四舍五入为两种不同的类型。