Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 将谓词类型实现为逆变单元组?_Haskell_Monads_Functor - Fatal编程技术网

Haskell 将谓词类型实现为逆变单元组?

Haskell 将谓词类型实现为逆变单元组?,haskell,monads,functor,Haskell,Monads,Functor,我很确定我可以证明,原则上,谓词类型构造函数是一个反单子,是单子的推广,其中函子是反变的,但我不确定它将如何实现 首先,让我们定义一些术语: class Contravariant f where contramap :: (b -> a) -> f a -> f b class ContraMonad m where return :: a -> m a join :: m(m a) -> m a contrabind :: m

我很确定我可以证明,原则上,
谓词
类型构造函数是一个
反单子
,是
单子
的推广,其中函子是反变的,但我不确定它将如何实现

首先,让我们定义一些术语:

class Contravariant f where
    contramap :: (b -> a) -> f a -> f b

class ContraMonad m where
    return :: a -> m a
    join :: m(m a) -> m a
    contrabind :: m a -> (m b -> a) -> m b

data Predicate a = Pred {getPred :: a -> Bool}

instance Contravariant Predicate where
    contramap f x = Pred ((getPred x).f)
这表明谓词是一个函数,它接受a的值并从中生成命题,它是从Hask到Hask^{op}的逆变函子。谓词的一个例子是:

isEven :: Integer -> Bool
isEven n = if (mod n 2 == 0)
           then True
           else False
函数
isEven
在数学意义上是一个谓词,而
Pred isEven
在这里实现的意义上是一个
谓词

谓词
实现为
对立面
更为棘手

返回只有一种自然选择

return :: a -> Predicate a
return x = Pred(const True)

你可以考虑“返回”的可能性,给出一个谓词,其中x是真的,没有A类型的其他元素是真的。问题是,这只能在a是

Eq
typeclass的成员时实现

join p = Pred(\x -> not ((getPred p) (\y -> y /= x)))
考虑连接比考虑约束更容易。显然,我们想要

contrabind x f = join.contramap f x
所以,当考虑到f是一个逆变函子时,约束尽可能类似于约束。函数
f
Pred b
转换为
a
,因此
contracmap f
Pred a
转换为
Pred(Pred b)

那么,
join
应该做什么呢?它必须将a类型谓词的谓词转换为a类型谓词。A型谓词的谓词对A型谓词作出判断。作为一个例子,考虑a=整数。
Pred(Pred Integer)
的一个例子是:

Pred("The predicate f is true for all even numbers.")
在这里,我使用了引号来代替实际的实现。如果f对所有的偶数都是真的,那么这句话就是真的。例如,
Pred isEven
将计算为
True

考虑到集合a上的谓词对应于a的子集这一事实,a
Pred(Pred a)
是一个函数的包装器,它接受a的所有子集并判断它们为“真”或“假”。我们希望
join
给我们一个谓词,这与给a的子集相同。这个子集应该尽可能无损。事实上,它应该关心每一个
Pred X
,w.r.t.
Pred(Pred X)
判断的真值。在我看来,自然的解决方案似乎是判断为“真”的所有子集的交集,这与将所有真谓词“和”在一起是一样的

predAnd :: (a -> Bool) -> (a -> Bool) -> (a -> Bool)
predAnd p q = \x -> ((getPred p) $ x) && ((getPred q) $ x)
例如,让我们回到“谓词f对于所有偶数都为真”。根据此判断,每个被评估为
true
的谓词对于所有偶数都必须为真,因此每个可能的子集都包含偶数。所有这些集合的交集只是一组偶数,因此
join
将返回谓词
Pred isEven


我的问题是,“加入”实际上是如何实现的?能否实施?我可以看到无限类型(如“Integer”)中出现的不可判定集的潜在问题,但它甚至可以实现为有限类型(如“Char”),其中甚至幂集也有有限基数?

有一些相关的东西,
Applicative
的逆变版本是,我在这里简化了它

class Contravariant f => Divisible f where
  divide  :: f b -> f c -> f (b, c)
  conquer :: f a
Data.Functor.Contravariant.Divisible
中的
divide
是根据
a->(b,c)
编写的,这突出了将
a
的工作划分为
b
c
的想法

{-# LANGUAGE RankNTypes #-}

-- The divide from Data.Functor.Contravariant.Divisible
divide' :: Divisible f => (a -> (b, c)) -> f b -> f c -> f a
divide' f b c = contramap f $ divide b c

-- And a proof they types are equivalent
proof :: (forall a b c. (a -> (b, c)) -> f b -> f c -> f a) -> f b -> f c -> f (b, c)
proof divide' = divide' id
任何
Op
都是
可除的
,如果其结果是
幺半群
。这是
谓词
的泛化,它是


但那是。

我想我可能已经想到了我自己问题的部分答案。首先,我们必须强制
a
进入
Eq
typeclass

join p = Pred(\x -> not ((getPred p) (\y -> y /= x)))
这是一个谓词,它接受一个
a
类型的元素,并从中构造一个谓词,即x为false,其他一切为true的谓词。然后,它根据原始的
Pred(preda)
判断对该谓词求值

如果该谓词为true,则x不在所有谓词的交集中,因此最终谓词将x发送到False。另一方面,如果该谓词为false,则不一定是
x
处于交叉点,除非我们制定一条附加规则:

如果
Pred(Pred a)
判断判定一个近似最大谓词为false,则该近似最大谓词中被判定为false的元素必须出现在所有判定为true的谓词中

因此,该规则允许“谓词f对所有偶数均为真”的判断,但不允许“谓词f仅对偶数为真”的判断。如果使用第一类判断,
join
将给出所有真谓词的交集。在第二种情况下,
join
将简单地给出一个谓词,该谓词有时可以告诉您是否不需要
x
。如果返回
False
x
肯定是不必要的。如果返回
True
,则测试不确定


我现在确信,除非类型
a
是有限的,否则完全实现“ANDing”是不可能的,即使这样,除非
a
非常小,否则也是不切实际的。

我注意到
\fx->contrabind(returnx)f::(mb->a->mb
。不知何故,我不喜欢我们如何扭转这些功能的方向:每一个违禁者都必须支持这一点,这似乎很难实现。另外,任何
b
contrabind(return())(const()):mb
看起来都很奇怪。函数被翻转,因为m是一个逆变函子。因此,来自
mb->a的函数变为来自
ma->
join p = Pred(\x -> not ((getPred p) (\y -> y /= x)))