Haskell:鼓励 GHC 推断正确的中间类型

标签 haskell ghc type-inference

我认为允许在 Haskell 中进行任意链式比较会很好,因此您可以进行简单的范围检查,例如:

x <= y < z

还有更复杂的东西,比如
x /= y < z == a

以上两者在语义上等价于
x <= y && y < z
x /= y && y < z && z == a

只是看看我是否能让语法工作。

因此,我使用了几个类型类来实现大部分目标:
{-# 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

由于中间类型的问题,它编译得很好,但似乎不太允许链接。
-- 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 = (<=)
checkRange1checkRange2工作正常,因为它们都对中间类型施加了约束(要么
作为第一次比较的结果,或作为第二次比较的参数)。
-- error
checkRange3 :: Ord a => a -> a -> a -> Bool
checkRange3 x y z = (x <= y) <= z

但是,当我试图让编译器推断中间类型时,它会向我咆哮。
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

有什么方法可以让编译器相信它应该使用 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

关于Haskell:鼓励 GHC 推断正确的中间类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9351401/

相关文章:

haskell - 如何编写一个函数,该函数的行为取决于变压器堆栈基础上的 monad

haskell - 使用 Haskell 绘制图形

haskell - 如何从 yesod 中的 PersistObjectId 获取字符串?

haskell - 构建 GHC : configure fails on happy despite successful cabal install

generics - ceylon max{} 的返回类型

java - Java 中的泛型类型推断限制

haskell - 理解 Haskell 作为模式

haskell - 我在哪里可以了解#ifdef?

haskell - 对上的foldr/foldl 似乎忽略第一个元组组件

haskell - 理解(,)<$>长度<*>头部的类型