如何使这个替代定义工作?

时间:2013-08-16 03:17:36

标签: haskell maybe

我刚刚发明了以下Maybe的替代定义:

type Maybe' a = forall b. (b -> (a -> b) -> b)

just :: a -> Maybe' a
just a = \d f -> f a

nothing :: Maybe' a
nothing = const

bind :: Maybe' a -> (a -> Maybe' b) -> Maybe' b
bind ma f = ma nothing (\a -> f a)

问题是我无法添加以下实例声明

instance Monad (Maybe') where
    return = just
    a >>= f = bind a f

错误消息是:

Type synonym Maybe' should have 1 argument, but has been given none

有什么办法可以解决吗?

3 个答案:

答案 0 :(得分:8)

如果将其包装在Monad中,则只能将其设为newtype的实例。您还必须使用PolymorphicComponents扩展名(RankNTypes的较弱形式)来普遍量化b

{-# LANGUAGE PolymorphicComponents #-}

newtype Maybe' a = Maybe' { unMaybe' :: forall b. (b -> (a -> b) -> b) }

just :: a -> Maybe' a
just a = Maybe' (\d f -> f a)

nothing :: Maybe' a
nothing = Maybe' const

bind :: Maybe' a -> (a -> Maybe' b) -> Maybe' b
bind ma f = Maybe' (unMaybe' ma const (\a -> unMaybe' (f a)))

instance Monad Maybe' where
    return = just
    (>>=)  = bind

你需要一个newtype的原因是Haskell类型的同义词不会“粘住”。当Haskell尝试将Maybe'的类型签名与Monad类型类的newtype匹配时,它根本看不到Maybe',而是看到原始底层函数类型。

Haskell使用“主要类型”来确保每种类型都具有普通形式。基础函数的正常形式是:

(->) b ((->) ((->) a b) b)

类型同义词不会更改类型的正常形式,但newtypes会更改。具体来说,在这种情况下,newtype正在重新排列类型,以便普通表单现在具有a作为Monad实例所需的最后一个类型参数。

答案 1 :(得分:6)

类型同义词不是类型。使用newtype,您将获得* -> *类型,而使用类型同义词则不会。所以你的问题现在已经减少为什么类型同义词不是一流的。

答案可能是因为第一类同义词会产生太多歧义,并且在简单的情况下无法进行类型推断。

type First a b = (a, b)
type Second a b = (b, a)
type Both a = (a, a)

如果我们可以定义Functor (First a)Functor (Second a)Functor (Both a)个实例,那么fmap (+1) (2, 3)将是不明确的。

您的发明BTW称为Church encoding。教会可以编码任何东西。请参阅https://gist.github.com/rampion/2176199以了解Haskell中的少数教会编码(对,可能和列表)。

答案 2 :(得分:1)

无法部分应用类型同义词。

类型同义词只是帮助程序员的简短手段,而不是Haskell语言可以讨论的实际存在的东西。 Haskell处理类型同义词的唯一方法是“查看”它以查看右侧的类型。参数只是给你一种“宏语言”。

所以Maybe' a完全等同于forall b. (b -> (a -> b) -> b)。它的行为就像你写了forall b. (b -> (a -> b) -> b)一样。但是Maybe'本身没有争论呢? Haskell不能像Maybe'那样处理它,它必须用其他东西替换它。但是什么?如果它意味着什么,那就必须是\a ~> (forall b. (b -> (a -> b) -> b),我使用\a ~> ...作为类型级lambda的伪语法;从类型到另一种类型的任意函数。我必须为此编写语法的原因是因为Haskell没有这个语法,并且它没有语法的原因是因为它无法处理完全通用的类型级函数。

我不确定支持任意类型级别的lambdas(类型构造函数和类型族是否实际上是非常有限的形式)实际上是不可能的,但它肯定是非常困难的。因此不能部分应用类型同义词。

要获得可以创建Monad实例的东西(需要可以应用于类型的东西来创建类型 - 某种类型* -> *),你需要使用{{1或data创建一个类型构造函数。类型同义词不能用于此目的。