- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
简单来说
我的 getter 和 setter 都可能失败,并带有描述如何失败的消息。因此他们返回 Either String
,这意味着我无法以正常方式用它们制作镜头。
详细
考虑这些类型:
import qualified Data.Vector as V
data Tree a = Tree { label :: a
, children :: V.Vector (Tree a) }
type Path = [Int]
Path
成
Tree
导致
Tree
,所以 getter 必须有像
getSubtree :: Path -> Tree a -> Either String (Tree a)
这样的签名. setter 需要一个类似的签名(参见下面的
modSubtree
)。
Tree a
的值,我会用它们来创建一个镜头,通过类似
lens
的东西函数在
Lens.Micro .但是,如果他们返回
Either
,我就不能这样做。 .因此我无法将它们与其他镜头组合在一起,因此我必须进行大量的包装和展开。
{-# LANGUAGE ScopedTypeVariables #-}
module I_wish_I_could_lens_this_Either where
import qualified Data.Vector as V
data Tree a = Tree { label :: a
, children :: V.Vector (Tree a) }
deriving (Show, Eq, Ord)
type Path = [Int]
-- | This is too complicated.
modSubtree :: forall a. Show a =>
Path -> (Tree a -> Tree a) -> Tree a -> Either String (Tree a)
modSubtree [] f t = Right $ f t
modSubtree (link:path) f t = do
if not $ inBounds (children t) link
then Left $ show link ++ "is out of bounds in " ++ show t
else Right ()
let (cs :: V.Vector (Tree a)) = children t
(c :: Tree a) = cs V.! link
c' <- modSubtree path f c
cs' <- let left = Left "imossible -- link inBounds already checked"
in maybe left Right $ modifyVectorAt link (const c') cs
Right $ t {children = cs'}
getSubtree :: Show a => Path -> Tree a -> Either String (Tree a)
getSubtree [] t = Right t
getSubtree (link:path) t =
if not $ inBounds (children t) link
then Left $ show link ++ "is out of bounds in " ++ show t
else getSubtree path $ children t V.! link
-- | check that an index into a vector is inbounds
inBounds :: V.Vector a -> Int -> Bool
inBounds v i = i >= 0 &&
i <= V.length v - 1
-- | Change the value at an index in a vector.
-- (Data.Vector.Mutable offers a better way.)
modifyVectorAt :: Int -> (a -> a) -> V.Vector a -> Maybe (V.Vector a)
modifyVectorAt i f v
| not $ inBounds v i = Nothing
| otherwise = Just ( before
V.++ V.singleton (f $ v V.! i)
V.++ after )
where before = V.take i v
after = V.reverse $ V.take remaining $ V.reverse v
where remaining = (V.length v - 1) - i
最佳答案
你确实可以用镜头做到这一点!或者更具体地说;遍历:)
首先进行一些设置:
{-# LANGUAGE OverloadedLists #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE RankNTypes #-}
module TreeTraversal where
import qualified Data.Vector as V
import Control.Lens hiding (children)
data Tree a = Tree { _label :: a
, _children :: V.Vector (Tree a) }
deriving (Show, Eq, Ord, Functor)
makeLenses ''Tree
type Path = [Int]
failover
;它接受一个遍历和一个函数,并将尝试在遍历上运行该函数,但它将以
Alternative
返回结果。语境;我们可以选择这个上下文为“可能”,这样我们就可以通过模式匹配检测失败并返回适当的
Left
或
Right
.我不知道遍历索引列表的简单方法,因此我编写了一个快速助手来递归链接列表并将它们转换为使用组合的遍历。
modSubtreeWithGenericError
:: forall a. Show a
=> Path -> (Tree a -> Tree a) -> Tree a -> Either String (Tree a)
modSubtreeWithGenericError links f =
maybe (Left "out of bounds") Right . failover (pathOf links) f
where
pathOf :: [Int] -> Traversal' (Tree a) (Tree a)
pathOf [] = id
pathOf (p : ps) = children . ix p . pathOf ps
Either String
内部运行。 ;大多数遍历必须在 ANY applicative 上工作,但在我们的例子中,我们知道我们希望我们的结果在任何一个中;所以我们可以利用这一点:
modSubtreeWithExpressiveError
:: forall a. Show a
=> [Int] -> (Tree a -> Tree a) -> Tree a -> Either String (Tree a)
modSubtreeWithExpressiveError links f = pathOf links %%~ (pure . f)
where
pathOf :: [Int] -> LensLike' (Either String) (Tree a) (Tree a)
pathOf [] = id
pathOf (x : xs) = childOrFail x . pathOf xs
childOrFail :: Show a => Int -> LensLike' (Either String) (Tree a) (Tree a)
childOrFail link f t =
if t & has (children . ix link)
then t & children . ix link %%~ f
else buildError link t
childOrFail
是有趣的一点;
LensLike
bit 实际上只是
(Tree a -> Either String (Tree a)) -> Tree a -> Either String (Tree a)
的别名这只是
traverse
专攻
Either String
;我们不能只使用
traverse
直接,因为我们只想遍历单个子树,我们的函数运行在
Tree a
上而不仅仅是
a
.我手动写了遍历,首先使用
has
检查目标是否存在然后要么失败并返回
Left
有一个很好的错误,或者运行
f
(代表其余的遍历)使用
%%~
在适当的 child 上.
%%~
组合器也有点吓人;具有讽刺意味的是,它的定义是字面意思
(%%~) = id
;通常我们会使用
%~
而是在这里;但它需要一个与
Either String
不匹配的特定 Applicative我们指定的一个。
%%~
愉快地运行我们的自定义遍历,尽管我们仍然需要添加一个额外的
pure
到我们的函数中以使其进入Either 上下文。
关于haskell - 当我的 getter 和 setter 返回 `Either` 时,我可以构建类似镜头的东西吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55189779/
这个fn是吗: function isplainobj ( obj ) { return Object.prototype.toString.call( obj ) === "[object
我尝试创建一个我没有经验的小 bash 脚本。我尝试做类似的事情: #!/bin/bash statut="na" if [ $proc = 0 ]; then statut = "close
我想重写 HighLine 的几个方法来自定义我的控制台,目前我的代码如下所示: cmd = ask("#{@prompt_label} #{@prompt_separator} ",
鉴于下面的 HTML,我尝试使用 jQuery 来匹配所有具有类“foo”的跨度的列表项,并且该跨度应包含文本“relevant”。 Some text relevant Some more
我拥有一个 5 美元 20GB SSD Digital Ocean Droplet,它几乎用完了 Docker 镜像和容器的空间。 有没有办法购买一个卷,将其连接到服务器并安全地将所有 Docker
我有这样的表: id name number result stuff stuff stuff stuff 我只想将 class = "red" 添加到
我需要计算两点之间的距离,但不是以常规方式。我需要知道“东西距离”+“南北距离”。我想这比常规的“乌鸦飞翔”计算更简单,但我仍然不知道如何做到这一点。 我想使用 MySQL 查询来执行此操作,并且最好
#include #include #include typedef struct dict_pair { void *key; void *value; struct dict_p
为什么当我尝试通过 将 char[] word 写入控制台时会发生这种奇怪的事情 Console.WriteLine(word); 我得到了一个正确的结果,但是当我写的时候 Console.Write
一个简单的例子: class C{} class B{ @Inject C c; void doSomething(){ System.out.println(c);
我想做某事,但不确定如何描述它。我有这门课 public class Company { private List _persons; private Person GetPersonByNa
我正在尝试实现我自己的 qDebug()样式调试输出流,这基本上是我目前所拥有的: struct debug { #if defined(DEBUG) template std::os
所以我正在为我的应用程序编写一个搜索功能,代码如下: - (void) selectObject: (NSString *)notes{ [axKnotes removeAllObjects]
我想在 Rust 中匹配一种复杂的继承式东西: struct Entity { pub kind: EntityKind, } pub enum EntityKind { Player
我是 SQL 新手。这没有返回任何结果...... SELECT media.id as mediaid, media.title as mediatitle, media.description
在微型 SDCard 上写入 Android things 图像并将该卡插入 Raspberry Pi 3 Model B 并打开电源,启动时显示“Auto config Please wait”然后
这是一个常见的但是文本出现在框的右侧,不是极右但几乎是这样 h3: ................................................ .................
#include #include #include #include #include int main(int argc, string argv[]) { if(argc >
所以我试图让一些东西相互堆叠。首先,查看工作链接会有所帮助,您会看到问题所在: http://brownbox.net.au/clients/matchlessphotography/ 现在我需要使用
我想在禁用 javascript 时在我的网站顶部显示一条消息(就像在 SO 上一样),但在谷歌浏览器上不起作用 最佳答案 看起来是这样。 您可以使用 javascript 隐藏“noscript”消
我是一名优秀的程序员,十分优秀!