Haskell 如何通过镜头覆盖默认值(仅当传入值不是空时)

Haskell 如何通过镜头覆盖默认值(仅当传入值不是空时),haskell,haskell-lens,Haskell,Haskell Lens,我基本上是试图覆盖记录中的一组默认值,但前提是特定于用户的值不是Nothing。有可能通过镜头来做吗 import qualified Data.Default as DD instance DD.Def Nouns where def = Nouns { -- default values for each field come here } lookupHStore :: HStoreList -> Text -> Maybe Text m

我基本上是试图覆盖记录中的一组默认值,但前提是特定于用户的值不是
Nothing
。有可能通过镜头来做吗

import qualified Data.Default as DD

instance DD.Def Nouns where
  def  = Nouns
    {
      -- default values for each field come here
    }

lookupHStore :: HStoreList -> Text -> Maybe Text

mkNounsFromHStoreList :: HStoreList -> Nouns
mkNounsFromHStoreList h = (DD.def Nouns)
  & depSingular .~ (lookupHStore h "dep_label_singular")
  -- ERROR: Won't compile because Text and (Maybe Text) don't match
使用而不是创建
Default
的实例怎么样

编辑:由于您似乎还想将
默认值
用于其他目的:

λ > import Data.Default
λ > import Data.Maybe
λ > :t fromMaybe def
fromMaybe def :: Default a => Maybe a -> a
这似乎就是您所追求的。

使用而不是创建
默认值的实例如何

编辑:由于您似乎还想将
默认值
用于其他目的:

λ > import Data.Default
λ > import Data.Maybe
λ > :t fromMaybe def
fromMaybe def :: Default a => Maybe a -> a

这似乎就是你想要的。

好吧,我找到了一个可能的解决方案,但我仍在寻找更好的解决方案

mkNounsFromHStoreList :: HStoreList -> Nouns
mkNounsFromHStoreList h = (DD.def Nouns)
  & depSingular %~ (overrideIfJust (lookupHStore h "dep_label_singular"))
  -- and more fields come here...
  where
    overrideIfJust val x = maybe x id val

好吧,我找到了一个可能的解决方案,但我仍在寻找更好的解决方案

mkNounsFromHStoreList :: HStoreList -> Nouns
mkNounsFromHStoreList h = (DD.def Nouns)
  & depSingular %~ (overrideIfJust (lookupHStore h "dep_label_singular"))
  -- and more fields come here...
  where
    overrideIfJust val x = maybe x id val
这似乎是我的工作。实现左偏选择-其
选择第一个非

import Control.Applicative
import Data.Semigroup

data Foo = Foo {
    bar :: Maybe Int,
    baz :: Maybe String
}
我将为
Foo
实现一个实例,它将
逐点提升到记录字段上。因此操作
xy
x
的匹配非
Nothing
字段覆盖
y
的字段。(您也可以使用,它也可以执行相同的操作。)


你可以用它做一件有趣的事情,就是把
可能
Foo
的定义中剔除

{-# LANGUAGE RankNTypes #-}

import Control.Applicative
import Data.Semigroup
import Data.Functor.Identity

data Foo f = Foo {
    bar :: f Int,
    baz :: f String
}
我最初在上面写的
Foo
现在相当于
Foo-Maybe
。但是现在您可以表达不变量,比如“this
Foo
已填充其所有字段”,而无需复制
Foo
本身

type PartialFoo = Foo Maybe  -- the old Foo
type TotalFoo = Foo Identity  -- a Foo with no missing values
仅依赖于
可能
备选方案
实例的
半群
实例保持不变

instance Alternative f => Semigroup (Foo f) where
    f1 <> f2 = Foo {
        bar = bar f1 <|> bar f2,
        baz = baz f1 <|> baz f2
    }
现在,有了一点
可遍历的
启发的直截了当的废话

-- "higher order functors": functors from the category of endofunctors to the category of types
class HFunctor t where
    hmap :: (forall x. f x -> g x) -> t f -> t g

-- "higher order traversables",
-- about which I have written a follow up question: https://stackoverflow.com/q/44187945/7951906
class HFunctor t => HTraversable t where
    htraverse :: Applicative g => (forall x. f x -> g x) -> t f -> g (t Identity)
    htraverse eta = hsequence . hmap eta
    hsequence :: Applicative f => t f -> f (t Identity)
    hsequence = htraverse id

instance HFunctor Foo where
    hmap eta (Foo bar baz) = Foo (eta bar) (eta baz)
instance HTraversable Foo where
    htraverse eta (Foo bar baz) = liftA2 Foo (Identity <$> eta bar) (Identity <$> eta baz)
对于你所需要的东西来说,这可能是过分的,但它仍然相当整洁。

这似乎是一份适合你的工作。实现左偏选择-其
选择第一个非

import Control.Applicative
import Data.Semigroup

data Foo = Foo {
    bar :: Maybe Int,
    baz :: Maybe String
}
我将为
Foo
实现一个实例,它将
逐点提升到记录字段上。因此操作
xy
x
的匹配非
Nothing
字段覆盖
y
的字段。(您也可以使用,它也可以执行相同的操作。)


你可以用它做一件有趣的事情,就是把
可能
Foo
的定义中剔除

{-# LANGUAGE RankNTypes #-}

import Control.Applicative
import Data.Semigroup
import Data.Functor.Identity

data Foo f = Foo {
    bar :: f Int,
    baz :: f String
}
我最初在上面写的
Foo
现在相当于
Foo-Maybe
。但是现在您可以表达不变量,比如“this
Foo
已填充其所有字段”,而无需复制
Foo
本身

type PartialFoo = Foo Maybe  -- the old Foo
type TotalFoo = Foo Identity  -- a Foo with no missing values
仅依赖于
可能
备选方案
实例的
半群
实例保持不变

instance Alternative f => Semigroup (Foo f) where
    f1 <> f2 = Foo {
        bar = bar f1 <|> bar f2,
        baz = baz f1 <|> baz f2
    }
现在,有了一点
可遍历的
启发的直截了当的废话

-- "higher order functors": functors from the category of endofunctors to the category of types
class HFunctor t where
    hmap :: (forall x. f x -> g x) -> t f -> t g

-- "higher order traversables",
-- about which I have written a follow up question: https://stackoverflow.com/q/44187945/7951906
class HFunctor t => HTraversable t where
    htraverse :: Applicative g => (forall x. f x -> g x) -> t f -> g (t Identity)
    htraverse eta = hsequence . hmap eta
    hsequence :: Applicative f => t f -> f (t Identity)
    hsequence = htraverse id

instance HFunctor Foo where
    hmap eta (Foo bar baz) = Foo (eta bar) (eta baz)
instance HTraversable Foo where
    htraverse eta (Foo bar baz) = liftA2 Foo (Identity <$> eta bar) (Identity <$> eta baz)

对于你所需要的东西,可能做得太多了,但它仍然很整洁。

你可以自己做一个组合器:

(~?) :: ASetter' s a -> Maybe a -> s -> s
s ~? Just a  = s .~ a
s ~? Nothing = id
您可以像
~
一样使用它:

mkNounsFromHStoreList :: HStoreList -> Nouns
mkNounsFromHStoreList h =
  DD.def
    & myNoun1 ~? lookupHStore h "potato"
    & myNoun2 ~? lookupHStore h "cheese"

您可以制作自己的组合器:

(~?) :: ASetter' s a -> Maybe a -> s -> s
s ~? Just a  = s .~ a
s ~? Nothing = id
您可以像
~
一样使用它:

mkNounsFromHStoreList :: HStoreList -> Nouns
mkNounsFromHStoreList h =
  DD.def
    & myNoun1 ~? lookupHStore h "potato"
    & myNoun2 ~? lookupHStore h "cheese"

其他事情需要默认实例,例如在UI中向用户显示默认值。对,如果需要,您仍然可以使用
default
实例。我认为,为了使用默认值,您需要的函数只是
fromaybe
fromaybe def
在本上下文中应具有类型
Maybe nomes->nomes
。:-)其他事情需要默认实例,例如在UI中向用户显示默认值。对,如果需要,您仍然可以使用
default
实例。我认为,为了使用默认值,您需要的函数只是
fromaybe
fromaybe def
在本上下文中应具有类型
Maybe nomes->nomes
。:-)你意识到了吗?
overrideIfJust==flip from maybe
?你意识到了吗?
overrideIfJust==flip from maybe
?我很难理解你想做什么。请包括
名词
存储列表
的定义、预期的输入/输出以及任何错误消息。我无法理解您试图执行的操作。请包括
名词
存储列表
的定义、预期输入/输出以及任何错误消息。谢谢。正是我需要的。也许应该向上游捐款。谢谢。正是我需要的。或许应该向上游捐款。