ama*_*loy 6 haskell functor higher-kinded-types
我最近定义了一个类型,我可能无法计算其字段:
data Foo = Foo {x, y :: Int, others :: NonEmpty Int}
data Input
computeX, computeY :: Input -> Maybe Int
computeOthers :: Input -> Maybe (NonEmpty Int)
Run Code Online (Sandbox Code Playgroud)
现在,我可能做的一件明显的事情就是使用liftA3
:
foo :: Input -> Maybe Foo
foo i = liftA3 Foo (computeX i) (computeY i) (computeOthers i)
Run Code Online (Sandbox Code Playgroud)
Foo
这很好用,但我认为推广到hold Maybe
s,然后将一种类型转换为另一种类型可能会很有趣Foo
。在一些类似的情况下,我可以给该Foo
类型一个类型参数并派生 Traversable。然后在创建之后Foo (Maybe Int)
,我可以使用 立即反转整个事情sequenceA :: Foo (Maybe Int) -> Maybe (Foo Int)
。但这在这里不起作用,因为我的函数没有给我一个NonEmpty (Maybe Int)
,它给了我一个Maybe (NonEmpty Int)
。
所以我想我应该尝试通过函子进行参数化:
data Foo f = Foo {x, y :: f Int, others :: f (NonEmpty Int)}
Run Code Online (Sandbox Code Playgroud)
但问题是,如何将 aFoo Maybe
变成 a Maybe (Foo Identity)
?显然我可以手工编写该函数:它与liftA3
上面的内容同构。但是,对于这种高阶类型,是否有一些与 Traversable 类似的东西,以便我可以对这个问题应用更通用的函数,而不是使用定制函数重新解决它?
此类数据类型称为“高级数据”(HKD)。通常使用泛型或 Haskell 模板来操作它们。
有一些类似的库higgledy
为 HKD 提供内置功能。我相信construct
这是您正在寻找的功能:
{-# LANGUAGE DeriveGeneric #-}
import Data.Generic.HKD
import GHC.Generics
import Data.Monoid
data Foo = Foo { x, y :: Int, z :: [Int] }
deriving (Generic, Show)
emptyFoo :: HKD Foo Last
emptyFoo = mempty
sampleFoo :: HKD Foo Last
sampleFoo = deconstruct (Foo 1 2 [3])
emptyFoo' :: Last Foo
emptyFoo' = construct emptyFoo
sampleFoo' :: Last Foo
sampleFoo' = construct sampleFoo
main = do
print emptyFoo'
print sampleFoo'
Run Code Online (Sandbox Code Playgroud)
这将打印:
Last {getLast = Nothing}
Last {getLast = Just (Foo {x = 1, y = 2, z = [3])}
Run Code Online (Sandbox Code Playgroud)
编辑:我刚刚发现一个更受欢迎的库是barbies
(higgledy 也取决于芭比娃娃)。您正在寻找的函数也作为以下应用程序存在于该库中btraverse
:
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE UndecidableInstances #-}
import Data.List.NonEmpty
import Barbies
import GHC.Generics
import Data.Functor.Identity
data Foo f = Foo {x, y :: f Int, others :: f (NonEmpty Int)}
deriving (Generic, FunctorB, TraversableB, ConstraintsB)
deriving instance AllBF Show f Foo => Show (Foo f)
f :: Applicative f => Foo f -> f (Foo Identity)
f = btraverse (fmap Identity)
main :: IO ()
main = do
print (f (Foo (Just 1) (Just 2) (Just (3 :| []))))
Run Code Online (Sandbox Code Playgroud)
这打印:
Just (Foo {x = Identity 1, y = Identity 2, others = Identity (3 :| [])})
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
131 次 |
最近记录: |