ram*_*ion 7 haskell type-inference ghc
我认为在Haskell中允许任意链式比较是很好的,所以你可以做简单的范围检查,如:
x <= y < z
Run Code Online (Sandbox Code Playgroud)
还有更复杂的东西
x /= y < z == a
Run Code Online (Sandbox Code Playgroud)
以上两者在语义上等同于
x <= y && y < z
x /= y && y < z && z == a
Run Code Online (Sandbox Code Playgroud)
只是看看我是否可以使语法工作.
所以我在那里使用了几个类型类的大部分方式:
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}
module ChainedOrd where
import Prelude hiding ((<), (<=), (>), (>=), (==), (/=))
class Booly v a where
truthy :: v -> a
falsy :: v -> a
instance Booly a Bool where
truthy = const True
falsy = const False
instance Booly a (Maybe a) where
truthy = Just
falsy = const Nothing
class ChainedOrd a b where
(<),(>),(<=),(>=),(==),(/=) :: (Booly b c) => a -> b -> c
infixl 4 <
infixl 4 >
infixl 4 <=
infixl 4 >=
infixl 4 ==
infixl 4 /=
instance Ord a => ChainedOrd a a where
x < y = case compare x y of LT -> truthy y ; _ -> falsy y
x > y = case compare x y of GT -> truthy y ; _ -> falsy y
x <= y = case compare x y of GT -> falsy y ; _ -> truthy y
x >= y = case compare x y of LT -> falsy y ; _ -> truthy y
x == y = case compare x y of EQ -> truthy y ; _ -> falsy y
x /= y = case compare x y of EQ -> falsy y ; _ -> truthy y
instance Ord a => ChainedOrd (Maybe a) a where
Just x < y = case compare x y of LT -> truthy y ; _ -> falsy y
Nothing < y = falsy y
Just x > y = case compare x y of GT -> truthy y ; _ -> falsy y
Nothing > y = falsy y
Just x <= y = case compare x y of GT -> falsy y ; _ -> truthy y
Nothing <= y = falsy y
Just x >= y = case compare x y of LT -> falsy y ; _ -> truthy y
Nothing >= y = falsy y
Just x == y = case compare x y of EQ -> truthy y ; _ -> falsy y
Nothing == y = falsy y
Just x /= y = case compare x y of EQ -> falsy y ; _ -> truthy y
Nothing /= y = falsy y
Run Code Online (Sandbox Code Playgroud)
由于中间类型的问题,编译很好,但似乎不允许链接.
-- works
checkRange1 :: Ord a => a -> a -> a -> Bool
checkRange1 x y z = x `lem` y <= z
where lem :: Ord a => a -> a -> Maybe a
lem = (<=)
-- works
checkRange2 :: Ord a => a -> a -> a -> Bool
checkRange2 x y z = (x <= y) `leb` z
where leb :: Ord a => Maybe a -> a -> Bool
leb = (<=)
Run Code Online (Sandbox Code Playgroud)
checkRange1并且checkRange2工作正常,因为它们都对中间类型施加约束(作为第一次比较的结果,或作为第二次比较的参数).
-- error
checkRange3 :: Ord a => a -> a -> a -> Bool
checkRange3 x y z = (x <= y) <= z
Run Code Online (Sandbox Code Playgroud)
当我试图让编译器推断出中间类型时,它会咆哮我.
ChainedOrd.hs:64:30:
Ambiguous type variable `a0' in the constraints:
(ChainedOrd a0 a) arising from a use of `<='
at ChainedOrd.hs:64:30-31
(Booly a a0) arising from a use of `<=' at ChainedOrd.hs:64:24-25
Probable fix: add a type signature that fixes these type variable(s)
In the expression: (x <= y) <= z
In an equation for `checkRange3': checkRange3 x y z = (x <= y) <= z
Run Code Online (Sandbox Code Playgroud)
有没有什么方法可以说服编译器它应该Maybe a用作中间类型a0令人满意Booly a a0, ChainedOrd a0 a,因为这是它知道的唯一实例?
如果不这样做,还有另一种方法可以进行任意比较链接工作吗?
infixl 4 ==?
class ChainedEq a b where
(==?) :: a -> b -> Maybe b
instance (Eq a) => ChainedEq (Maybe a) a where
x ==? y = if x == Just y
then x
else Nothing
instance (Eq a) => ChainedEq a a where
x ==? y = if x == y
then Just x
else Nothing
unChain :: Maybe a -> Bool
unChain Nothing = False
unChain (Just _) = True
test :: Int -> Int -> Int -> Bool
test x y z = unChain $ x ==? y ==? z
Run Code Online (Sandbox Code Playgroud)