【问题标题】:generalize maybe and either functions in haskell概括可能和haskell中的任何一个功能
【发布时间】:2014-05-10 13:22:25
【问题描述】:

haskell 中是否有一个函数可以概括可能和任一函数?

例如,我想象一个这样的函数:

generalizedFunc :: SOMETHING m => b -> (a -> b) -> m a -> b
generalizedFunc valForError f value = ...

在 ghci 中使用它看起来像这样:

> generalizedFunc "bye" (\_ -> "hello") (Just 3)
"hello"
> generalizedFunc "bye" (\_ -> "hello") Nothing
"bye"
> generalizedFunc "bye" (\_ -> "hello") (Right 3)
"hello"
> generalizedFunc "bye" (\_ -> "hello") (Left "error")
"bye"

注意:Tom Ellis 提出了一个很好的观点,即这不是 Either 的泛化,而是一种特殊化。

【问题讨论】:

    标签: generics haskell


    【解决方案1】:

    是的。你要找的是Data.Foldable。它将foldr(用于列表)推广到任何代数数据类型:

    Data.List.foldr     :: (a -> b -> b) -> b     ->   []       a -> b
    maybe               :: b -> (a -> b)          ->   Maybe    a -> b
    either              :: (a -> c) -> (b -> c)   ->   Either a b -> c
    ---
    Data.Foldable.foldr :: Foldable t
                        => (a -> b -> b) -> b     ->   t        a -> b
    

    您的代码将从generalizedFunc "bye" (\_ -> "hello") 更改为foldr (\_ _ -> "hello") "bye"。确保告诉编译器您的意思是来自Data.Foldablefoldr;请参阅模块的文档。

    很遗憾,您的 GHC 版本可能缺少 Foldable (Either a) 实例,但自己编写一个应该相对容易。

    【讨论】:

    • Data.Foldable 实际上只是提供了从其他数据类型到[] 的映射。 Data.Functor.Foldable 提供了 foldr 的真正泛化,命名为 cata
    • @Carl:是的,在某种程度上。 foldMap 是一种更好的思考方式。但对于大多数应用程序,Data.Foldable(或Data.Traversable)就足够了。抱怨“你不需要成为类别理论专家才能使用 Haskell”直接Data.Functor.Foldable 之类的人;它看起来使用起来像一个非常麻烦的库,由于缺乏适当的文档而变得更糟。
    • @Carl:你能展示一个使用 cata 编写我原来的例子的例子吗?我不明白这些类型。
    • @illabout 我写了an example of using cata,它主要说明了为什么recursion-schemes 包在现实世界中很少使用。它确实成功地抽象了多态性,但使用它是一件非常痛苦的事情,除非你的所有数据类型都已经定义为定点并且你的所有逻辑都用代数表示。
    【解决方案2】:

    我想这有点自我推销,但我会发布它,因为它非常相关。

    不久前我写了一个名为generic-church 的小型库。这导出具有两个函数的单一类型类。要使用它,只需执行类似的操作

    {-# LANGUAGE DeriveGeneric #-}
    import GHC.Generics
    import Data.Church
    
    data Nat = Z | S Nat
    
    instance ChurchRep Nat
    

    请注意,Nat 不必像 Foldable 那样是函子。

    然后我们可以启动 GHCi 并执行类似的操作

    *> (toChurch Z) 'a' (const 'b')
      'a'
    *> (toChurch $ S Z) 'a' (const 'b')
      'b'
    

    foldr 不同,您可以自动将教堂表示转换回具体数据类型

    *> fromChurch (\a b -> a) :: Nat
      Z
    *> fromChurch (a b -> b Z) :: Nat
      S Z
    

    现在,与 catamorphisms/folds 相比,一个明显的缺点是 generic-church 目前以一种有点幼稚的方式处理递归数据类型(尽管我现在正在寻找修复这个问题)。也就是说,它将任何递归类型视为在其教堂表示中展开了一层,因此Nat 的教堂表示为

    type Nat' = forall c. c -> (Nat -> c) -> c
    

    编辑,你的generalFunc

    这是编写generalFunc 的代码,它实际上概括了maybe。我需要一个函数toChurchP,它位于generic-church-0.2 中,在我输入之前大约5 分钟上传。如果您想运行此代码,请务必使用cabal update :)

    {-# LANGUAGE DeriveGeneric, MultiParamTypeClasses, FlexibleInstances, TypeFamilies, ScopedTypeVariables #-}
    module So where
    import Data.Church
    import GHC.Generics
    import Data.Proxy
    
    -- Generalize of const. Allows us to use more than just Either
    -- for gmaybe
    class GConst a r where
      gconst :: r -> a
    instance GConst r' r => GConst (a -> r') r where
      gconst r = const (gconst r)
    instance GConst r r where
      gconst = id
    
    gfail :: forall a e s e' r. 
              (ChurchRep a, GConst e' e, Church a r ~ (e' -> s -> r)) =>
               e -> s -> a -> r
    gfail e s a = toChurchP (Proxy :: Proxy r) a (gconst e :: e') s
    

    这取决于gconst 吞下所有给失败结果e 的参数。一个聪明的定义应该允许类似

    > gfail id (const 'a') $ Left 'b'
      'b'
    

    但我目前的表述需要-XIncoherentInstances(哎呀!)。我希望能更新一个能同时概括eithermaybe 的版本。

    虽然如此,这仍然有点漂亮。

    *So> gfail True id (Just False)
    False
    *So> gfail True (id :: Bool -> Bool) Nothing
    True
    *So> gfail 'a' (const 'b') (Left ())
    'a'
    *So> gfail 'a' (const 'b') (Right ())
    'b'
    *So> :set -XDeriveGeneric
    *So> data MyMaybe = Fail | Yay Int deriving (Show, Generic)
    *So> instance ChurchRep MyMaybe
    *So> gfail 'a' (const 'b') (Yay 1)
    'b'
    

    【讨论】:

    • 这听起来很酷,但由于我缺乏使用 Haskell(和范畴理论)的经验,我很难理解这与可能和两种方法之间的关系。你能用你的库重写我原来的例子generalizedFunc吗?
    猜你喜欢
    • 2015-01-05
    • 2016-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-15
    • 2023-03-11
    相关资源
    最近更新 更多