【问题标题】:Haskell - Maybe EitherHaskell - 也许是
【发布时间】:2014-06-25 11:03:36
【问题描述】:
-- | 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 可以。这是 a 或 b 但 Either a aa?!

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

【问题讨论】:

    标签: haskell either


    【解决方案1】:

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

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

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

    这意味着Bool 只能是TrueFalse,但Either a b 可以是Left aRight 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 7Nothing

    类似地,Either Int Char 类型的东西可能是 Left 5Right 'c'

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

    所以Either Int Char 类型的东西要么是Int 要么是Char,但Either Int Int 类型的东西要么是Int 要么是Int。除了Int,您无法选择任何其他内容,但您会知道是Left 还是Right

    为什么有人问你这个问题/背后的想法

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

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

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

    反之亦然。

    (如果你没见过,$ 是由f $ x = f x 定义的,但$ 的优先级很低(infixr 0 $),所以f . g $ x(f . g) $ x,也就是(f . g) x. 是函数组合,所以(f.g) x = f (g x)。为了节省一对括号,这是很多解释!)

    接受或返回函数的函数

    当你不习惯的时候,这可能会让你一开始会有点头晕。

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

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

    functionFromBoolToPair f = ...
    

    但是我们可以用 f 做什么呢?好吧,对给定的函数最简单的事情就是将它应用于一个值。我们可以在什么值上使用f?那么f :: (Bool -> a) 所以它需要一个Bool 并给你一个a,所以我们可以做f Truef 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 = ....
    

    另一种感觉可能更简单的方法是创建一个letwhere 子句来定义一个名为f 之类的函数,其中f :: Bool -> a

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

    玩得开心。乱来。

    【讨论】:

    • 我想要的只是提示 :-) 也许我应该在开篇文章中写下。因为我真的很想明白。所以谢谢你的帮助。我之前检查了hoogle,但我并没有真正帮助。但是你的模式是一个好的开始..
    • @fuuman 你知道我是如何从定义到模式的吗?这是一项关键技能,如果不是,我将编辑该步骤的更多说明。
    • 感谢您提供的信息。与可能的比较和背后的思考部分非常有帮助!
    • 我们的导师给了我们另外两对函数。并且在文件中总是有测试。它们看起来像你的 ;) maybeToEitherUnit (eitherUnitToMaybe (Right 'a')) ~?= Right 'a', eitherUnitToMaybe (maybeToEitherUnit (Just 5)) ~?= Just 5 所以我明白你的意思了。
    【解决方案2】:

    注意Either a b 也称为ab 类型的联积或sum 可能很有用。确实现在很普遍使用

    type (+) = Either
    

    然后您可以将Either a b 写为a + b

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

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

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

    data Bool = True | False
    

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

    type 2 = Bool
    

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

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

    您已经猜到了:元组也称为产品。所以(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对于几乎任何有趣的类型,实际上都有无限多可能的值,但这种朴素的算术仍然会让你感到惊讶。

    【讨论】:

    • +1 我喜欢那里的类型算术。这让我想起了我给数学本科生讲授基数的讲座课程。当我使用柯里化作为 (C^B)^A 和 C^(AxB) 之间的双射时,这让他们大吃一惊。我很确定他们都不是函数式程序员。
    【解决方案3】:

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

    是的。尝试找出类型aEither a a 之间的区别。 Eitherdisjoint union。一旦你了解了aEither a a 之间的区别,你的功课应该很容易结合 AndrewC 的答案。

    【讨论】:

      【解决方案4】:

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

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

      (Bool, a) 对转换为Either a a 对背后的想法可能看起来有点棘手,但想想TrueFalseLeftRight 之间的对应关系。

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

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

      【讨论】:

      • (Bool -> a) to (a, a) 是我最大的问题。其余的现在都好了。我的意思是,我得到一个函数作为输入?那看起来像什么?我不知道这样做。到目前为止谢谢!
      • @fuuman 好吧,您将拥有一个看起来像“f True = someA,f False = someOtherA”的函数,并且您将其输入到这样的函数中:functionFromBoolToPair f。你能做些什么来从这个函数中得到两个不同的as?
      • @fuuman 如果我给你一个只有两个可能输入和两个可能输出的函数,你怎么能得到两个可能的输出?想象一个数学函数 f(0) = x, f(1) = y。给定函数 f,如何同时获得 x 和 y?
      • 我会采用两个可能的输入并将它们放入函数中。然后我会得到两个可能的输出。那么模式匹配是正确的选择吗?但我目前无法处理这个高阶函数.. 将函数作为输入.. :\ 抱歉,函数式编程不是我最喜欢的 :D 仍在思考 OO。
      • 啊,现在我明白了。谢谢!
      猜你喜欢
      • 1970-01-01
      • 2013-04-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多