0
-- | Convert a 'Maybe a' to an equivalent 'Either () a'. Should be inverse
-- to 'eitherUnitToMaybe'.
maybeToEitherUnit :: Maybe a -> Either () a
maybeToEitherUnit a = error "Not yet implemented: maybeToEitherUnit"

-- | Convert a 'Either () a' to an equivalent 'Maybe a'. Should be inverse
-- to 'maybeToEitherUnit'.
eitherUnitToMaybe :: Either () a -> Maybe a
eitherUnitToMaybe = error "Not yet implemented: eitherUnitToMaybe"

-- | Convert a pair of a 'Bool' and an 'a' to 'Either a a'. Should be inverse
-- to 'eitherToPairWithBool'.
pairWithBoolToEither :: (Bool,a) -> Either a a
pairWithBoolToEither = undefined  -- What should I do here?

-- | Convert an 'Either a a' to a pair of a 'Bool' and an 'a'. Should be inverse
-- to 'pairWithBoolToEither'.
eitherToPairWithBool :: Either a a -> (Bool,a)
eitherToPairWithBool = undefined  -- What should I do here?

-- | Convert a function from 'Bool' to 'a' to a pair of 'a's. Should be inverse
-- to 'pairToFunctionFromBool'.
functionFromBoolToPair :: (Bool -> a) -> (a,a)
functionFromBoolToPair = error "Not yet implemented: functionFromBoolToPair"

-- | Convert a pair of 'a's to a function from 'Bool' to 'a'. Should be inverse
-- to 'functionFromBoolToPair'.
pairToFunctionFromBool :: (a,a) -> (Bool -> a)
pairToFunctionFromBool = error "Not yet implemented: pairToFunctionFromBool"

我真的不知道该怎么办。我知道可能是什么,但我认为这两者都有问题,因为Either a a在我看来这毫无意义。Either a b会好的。Either a a这是 a 或 b 但是a?!

我一般不知道如何编写这些函数。

4

4 回答 4

16

鉴于我认为这是家庭作业,我不会回答,但会给出重要提示:

如果您在 hoogle ( http://www.haskell.org/hoogle/ ) 上查找定义,您会发现

data Bool = True | False
data Either a b = Left a | Right b

这意味着Bool只能是Trueor False,但Either a b可以是Left aor Right b

这意味着你的函数应该看起来像

pairWithBoolToEither :: (Bool,a) -> Either a a
pairWithBoolToEither (True,a) = ....
pairWithBoolToEither (False,a) = ....

eitherToPairWithBool :: Either a a -> (Bool,a)
eitherToPairWithBool (Left a) = ....
eitherToPairWithBool (Right a) = ....

比较Maybe

Maybe a是(谁)给的

data Maybe a = Just a | Nothing

所以某种类型的东西Maybe Int可能是Just 7or Nothing

类似地,类型Either Int Char可以是Left 5or Right 'c'

某种类型的东西Either Int Int可能是Left 7or Right 4

所以有类型Either Int Char的东西要么是 an 要么是Inta Char,但类型Either Int Int的东西要么是 anInt要么是Int。您不能选择除 以外的任何东西Int,但您会知道它是 aLeft还是 a Right

为什么你被问到这个/背后的想法

如果你有一些 type Either a a,那么数据(例如5in Left 5)总是 type a,而你只是用Leftor标记了它Right。如果你有一些类型(Bool,a)的东西a-data (例如5in (True,5))总是相同的类型,并且你已经将它与Falseor配对True

可能看起来不同但实际上具有相同内容的两件事的数学词是“同构”。你的导师要求你编写一对显示这种同构的函数。如果做些什么pairWithBoolToEither . eitherToPairWithBool,你的答案会更好,即不改变任何东西。实际上,我刚刚发现了您问题中的评论,其中说它们应该是相反的。在您的文章中,您应该通过在 ghci 中进行测试来展示这一点eitherToPairWithBool . pairWithBoolToEitherid

ghci> eitherToPairWithBool . pairWithBoolToEither $ (True,'h')
(True,'h')

反之亦然。

(如果您还没有看到它,$它定义为f $ x = f x$具有非常低的优先级 ( infixr 0 $),所以which f . g $ xis (f . g) $ xjust (f . g) xand .is function composition,所以(f.g) x = f (g x). 这是保存一对括号的很多解释!)

接受或返回函数的函数

当您不习惯时,这可能会让您一开始感到震惊。

functionFromBoolToPair :: (Bool -> a) -> (a,a)

唯一可以与函数进行模式匹配的只是一个变量f,所以我们需要做一些类似的事情

functionFromBoolToPair f = ...

但是我们能用它做什么f呢?好吧,对给定的函数最简单的事情就是将它应用于一个值。我们可以使用什么值f?好吧f :: (Bool -> a),所以它需要 aBool并给你一个a,所以我们可以做f Trueor f False,他们会给我们两个(可能不同的)类型值a。现在这很方便,因为我们需要a重视,不是吗?

接下来看看

pairToFunctionFromBool :: (a,a) -> (Bool -> a)

我们可以为类型做的模式匹配(a,a)是这样的(x,y),所以我们需要

pairToFunctionFromBool (x,y) = ....

但是我们怎样才能(Bool -> a)在右手边返回一个函数呢?

有两种方法我认为你会发现最简单。一个是注意,因为->无论如何都是右关联的,所以类型(a,a) -> (Bool -> a)是相同的,(a,a) -> Bool -> a所以我们实际上可以将要返回的函数的参数移动到 = 符号之前,如下所示:

pairToFunctionFromBool (x,y) True  = ....
pairToFunctionFromBool (x,y) False = ....

另一种感觉可能更简单的方法是创建一个letorwhere子句来定义一个称为类似的函数f,其中f :: Bool -> a< 有点像:

pairToFunctionFromBool (x,y) = f where
  f True = ....
  f False = ....

玩得开心。乱来。

于 2014-06-25T11:13:04.197 回答
6

也许有必要注意它Either a b也称为类型和的协积或总和。确实,现在很普遍使用ab

type (+) = Either

然后你可以Either a b写成a + b.

eitherToPairWithBool :: (a+a) -> (Bool,a)

现在常识会要求我们重写a + a2 ⋅ a. 信不信由你,这正是您要转换为的元组类型的含义!

解释一下:代数数据类型大致可以看作是“将可能构造的数量计数为1 ”。所以

data Bool = True | False

有两个构造函数。所以有点(这不是有效的Haskell!)

type 2 = Bool

元组允许来自每个参数的构造函数的所有组合。因此,例如在 中(Bool, Bool),我们有值

      (False,False)
      (False,True )
      (True, False)
      (True, True )

您已经猜到了:元组也称为products。所以类型(Bool, a)基本上是2 ⋅ a:对于每个值x :: a,我们可以创建(False, x)元组和(True, x)元组,总共是值的两倍x

几乎相同的事情Either a a:我们总是同时拥有Left xRight x作为可能的价值。

您所有具有“算术类型”的函数:

type OnePlus = Maybe

maybeToEitherUnit :: OnePlus a -> () + a
eitherUnitToMaybe :: () + a -> OnePlus a
pairWithBoolToEither :: 2 ⋅ a -> a + a
eitherToPairWithBool :: a + a -> 2 ⋅ a
functionFromBoolToPair :: a² -> a⋅a
pairToFunctionFromBool :: a⋅a -> a²

1对于几乎任何有趣的类型,实际上都有无限多的可能值,但这种朴素的算术仍然让你出奇地远。

于 2014-06-25T16:18:08.323 回答
1

Either a a在我看来毫无意义。

是的,它确实。尝试找出 typeaEither a a. Either是一个不相交的联合。一旦您了解 和 之间的区别aEither a a您的作业应该很容易结合 AndrewC 的答案。

于 2014-06-25T11:28:33.423 回答
1

请注意,Either a b从字面上看,这种类型的值可以是 ana或 an a。听起来您实际上已经掌握了这个概念,但是您缺少的部分是Either类型区分了用构造的值Left和构造的值Right

对于第一部分,想法是Maybe要么Just是事物,要么是Nothing--Nothing对应,()因为两者都是“本质上”的数据类型,只有一个可能的值。

(Bool, a)将pair转换为 pair 背后的想法Either a a可能看起来有点棘手,但只要想想TrueandFalseLeftand之间的对应关系Right

至于将类型函数转换(Bool -> a)(a, a)对,这里有一个提示:考虑只能有两种类型的事实Bool,并写下初始函数参数的样子。

希望这些提示可以帮助您入门。

于 2014-06-25T15:17:20.337 回答