类型的总函数(forall n。可能(f n)) - >也许(forall n。(f n))

时间:2011-10-11 00:14:39

标签: haskell types polymorphism

是否可以编写

类型的内射函数
hard :: (forall n . Maybe (f n)) -> Maybe (forall n . (f n))

作为total functional program - 也就是说,不使用errorundefinedunsafeXXXbottom,无穷无尽的模式,或任何 不终止的功能?

parametricity,任何固定f :: *->*的唯一总数

的居民
(forall n . Maybe (f n))

将采用以下两种形式之一:

Nothing

Just z
  where
    z :: forall n . f n

不幸的是,caseMaybe的所有尝试都需要 首先选择n ,然后选择模式变量的类型 案例分支在n中将不再是多态的。好像是 语言缺少某种表现形式 case - 对多态类型的歧视而不实例化 输入

顺便说一句,在相反方向编写函数很容易:

easy :: Maybe (forall n . (f n)) -> (forall n . Maybe (f n))
easy Nothing  = Nothing
easy (Just x) = Just x

4 个答案:

答案 0 :(得分:4)

我恰巧得到了它,只是尝试创建一个我可以传递到easyf函数的值。如果你需要解释,我会遇到麻烦!! 见下面的评论。

data A α = A Int
data B f = B (forall α . f α)

a :: forall α . A α
a = A 3

b = B a
f (B (Just -> x)) = x -- f :: B t -> Maybe (forall α. t α)
f' (B x) = Just x -- f' :: B t -> Maybe (t α)

easy :: forall f . Maybe (forall n . (f n)) -> (forall n . Maybe (f n))
easy Nothing = Nothing
easy (Just x) = Just x

easyf :: Maybe (forall n . (A n)) -> (forall n . Maybe (A n))
easyf = easy

-- just a test
g = easyf (f b)



h :: (forall α. t α) -> Maybe (forall α. t α)
h = f . B

unjust :: (forall n . (Maybe (f n))) -> (forall n . f n)
unjust (Just x) = x

hard :: forall f. (forall n . (Maybe (f n))) -> Maybe (forall n . (f n))
hard xj@(Just _) = g (unjust xj) where
    g :: (forall n . f n) -> Maybe (forall n . (f n))
    g = h
hard Nothing = Nothing

编辑1

从上面拿出垃圾,

mkJust :: (forall α. t α) -> Maybe (forall α. t α)
mkJust = Just

unjust :: (forall n . (Maybe (f n))) -> (forall n . f n)
unjust (Just x) = x

hard :: forall f. (forall n . (Maybe (f n))) -> Maybe (forall n . (f n))
hard xj@(Just _) = mkJust (unjust xj)
hard Nothing = Nothing

答案 1 :(得分:2)

我证明这是不可能的[错误,不,我没有;见Agda:

module Proof where

open import Data.Empty
open import Data.Maybe
open import Data.Bool
open import Data.Product

open import Relation.Nullary
open import Relation.Binary.PropositionalEquality

Type : Set₁
Type = Σ ({A : Set} {F : A → Set} → (∀ n → Maybe (F n)) → Maybe (∀ n → F n)) (λ f → ∀ {A} {F : A → Set} x y → f {F = F} x ≡ f y → (∀ i → x i ≡ y i))

helper : (b : Bool) → Maybe (T b)
helper true = just _
helper false = nothing

proof : ¬ Type
proof (f , pf) with inspect (f helper)
proof (f , pf) | just x with-≡ eq = x false
proof (f , pf) | nothing with-≡ eq with f {F = T} (λ _ → nothing) | pf helper (λ _ → nothing)
proof (f , pf) | nothing with-≡ eq | just x | q = x false
proof (f , pf) | nothing with-≡ eq | nothing | q with q eq true
proof (f , pf) | nothing with-≡ eq | nothing | q | ()

当然,这不是一个完美的反对,因为它是用不同的语言,但我认为它匹配得相当好。

我开始将Type定义为你想要的函数的类型,同时证明函数是单射的(ΣxP可以看作是一个存在主义的说法“存在一个x,使得P(x)” )。因为我们讨论的是一个带有函数的内射函数(haskell的forall可以看作是一个类型级函数,而这就是它在Agda中的编码方式),我使用了逐点相等(∀ i → x i ≡ y i),因为Agda的逻辑不会让我直接证明x ≡ y

除此之外,我只是通过对布尔值提供反例来反驳这种类型。

编辑:我刚刚意识到类型涉及从某种类型F到类型的函数A,因此我的证明与您在Haskell中编写的内容不完全对应。我现在很忙,但可能会稍后尝试解决这个问题。

编辑2:我的证明无效,因为我没有考虑参数。我可以在布尔上进行模式匹配,但不能在套装上进行模式匹配,我无法在Agda中证明这一点。我会更多地考虑这个问题:)

答案 2 :(得分:1)

如果您查看所有可能的计算依赖项,这很容易理解,每个计算值可能在运行时都有:

(forall n . Maybe (f n))类型的表达式可以为一种类型评估为Nothing,为另一种类型评估为Just。因此,它是一个将类型作为参数的函数。

hard :: (forall n . Maybe (f n)) -> Maybe (forall n . f n)
-- problem statement rewritten with computational dependencies in mind:
hard' :: (N -> Maybe (fN)) -> Maybe (N -> fN)

Maybe (N -> fN)类型的结果值(NothingJust)取决于N的值(n的类型)

所以答案是没有

答案 3 :(得分:0)

问题可以简化为以下问题:我们可以编写一个以下列方式移动foralls的函数吗?

suicidal :: f (forall n. n) -> forall n. f n

毕竟,如果我们能够做到这一点,那么其余的很容易用一些不可预测的类型:

hard' :: Maybe (f (forall n. n)) -> Maybe (forall n. f n)
hard' Nothing = Nothing
hard' (Just x) = Just (suicidal x)

hard :: (forall n. Maybe (f n)) -> Maybe (forall n. f n)
hard x = hard' x -- instantiate 'n' at type 'forall n. n', thank goodness for impredicativity!

(如果您想在GHC中尝试此操作,请务必定义类似

的新类型
newtype Forall f = Forall { unForall :: forall n. f n }

因为否则GHC喜欢将forall漂浮到箭头前面并将你搞砸。)

但我们是否可以写suicidal的答案很明确:不,我们不能!至少,不是以f为参数的方式。解决方案必须看起来像这样:

suicidal x = /\ n. {- ... -}

...然后我们必须走过f的“结构”,找到有类型函数的“地方”,然后将它们应用到我们现在可用的n 。关于hard的原始问题的答案结果是相同的:我们可以针对任何特定hard编写f,但不会针对所有f编写参数。

顺便说一句,我不相信你所说的关于参数的说法是对的:

  

通过参数化,对于任何固定f :: *->*(forall n . Maybe (f n))的唯一总居民将采用以下两种形式之一:NothingJust z其中z :: forall n . f n。< / p>

实际上,我认为你得到的是居民(观察上等同于)两种形式之一:

/\ n. Nothing
/\ n. Just z

...上面的z 多态:其具有特定类型f n。 (注意:那里没有隐藏的forall。)也就是说,后一种形式的可能术语取决于f!这就是为什么我们不能以f为参数编写函数。

编辑:顺便说一下,如果我们允许自己Functor f实例,那么事情当然更容易。

notSuicidal :: (forall a b. (a -> b) -> (f a -> f b)) -> f (forall n. n) -> forall n. f n
notSuicidal fmap structure = /\ n. fmap (\v -> v [n]) structure

...但这是作弊,尤其是因为我不知道如何将其转换为Haskell。 ; - )

相关问题