为列表创建镜头(如)
Creating a lens(like) for list
我正在尝试为以下数据结构创建镜头。我正在使用 lens-family
.
data Tree = Tree {
_text :: String,
_subtrees :: [Tree]
} deriving (Show,Eq,Read,Generic)
出于各种原因,我想避免使用模板 Haskell。首先,它似乎不适用于我的 ghc (7.8.3) 版本,这是另一个(超出范围)问题。
为唱片制作镜头并不难。
text :: Lens' Tree String
text f (Tree text' subtrees') =
(\text'' -> Tree text'' subtrees') `fmap` (f text')
subtrees :: Lens' Tree [Tree]
subtrees f (Tree text' subtrees') =
(\subtrees'' -> Tree text' subtrees'') `fmap` (f subtrees')
但是lens-family好像没有默认的镜头列表。我认为这是可能的。有为lens
package。这些是我失败的尝试:
import Lens.Family2
import Lens.Family2.Unchecked
-- List lenses
_last :: Lens [a] [a'] a a'
_last f l =
-- first try
--lens getter setter
-- second try
(\el -> (init l) ++ el) `fmap`(f (last l))
where
getter = last
setter l el = l ++ el
他们都遇到了与此类似的错误:
Could not deduce (a' ~ [a'])
from the context (Functor f)
bound by the type signature for
_last :: Functor f => LensLike f [a] [a'] a a'
at editor.hs:22:10-27
‘a'’ is a rigid type variable bound by
the type signature for
_last :: Functor f => LensLike f [a] [a'] a a'
at editor.hs:22:10
Expected type: f [a']
Actual type: f a'
Relevant bindings include
f :: a -> f a' (bound at editor.hs:23:7)
_last :: LensLike f [a] [a'] a a' (bound at editor.hs:23:1)
In the second argument of ‘fmap’, namely ‘(f (last l))’
In the expression: (\ el -> (init l) ++ el) `fmap` (f (last l))
如何定义_last
镜头?
编辑: 这是构建的版本:
_last f l = (\el -> (init l) ++ [el]) `fmap`(f (last l))
不过,正如David/Daniel指出的那样,_last
应该是遍历,而不是镜头。
您在 el
周围缺少方括号((++)
需要一个包含两个参数的列表)。如果你把它们放进去,你的第一次尝试应该会成功。你的类型也太笼统了。 Haskell 中的列表不是异构的,因此它们只能包含一种类型的值。
此外,正如 Daniel Wagner 所说,这不可能是真实的镜头,因为它是局部的。您链接到的镜头文档已过时。当前的镜头库有 _last
as a Traversal
可以避免这个问题,因为 Traversal
可以有 0 个或多个目标,而镜头必须恰好有 1 个。
我正在尝试为以下数据结构创建镜头。我正在使用 lens-family
.
data Tree = Tree {
_text :: String,
_subtrees :: [Tree]
} deriving (Show,Eq,Read,Generic)
出于各种原因,我想避免使用模板 Haskell。首先,它似乎不适用于我的 ghc (7.8.3) 版本,这是另一个(超出范围)问题。
为唱片制作镜头并不难。
text :: Lens' Tree String
text f (Tree text' subtrees') =
(\text'' -> Tree text'' subtrees') `fmap` (f text')
subtrees :: Lens' Tree [Tree]
subtrees f (Tree text' subtrees') =
(\subtrees'' -> Tree text' subtrees'') `fmap` (f subtrees')
但是lens-family好像没有默认的镜头列表。我认为这是可能的。有为lens
package。这些是我失败的尝试:
import Lens.Family2
import Lens.Family2.Unchecked
-- List lenses
_last :: Lens [a] [a'] a a'
_last f l =
-- first try
--lens getter setter
-- second try
(\el -> (init l) ++ el) `fmap`(f (last l))
where
getter = last
setter l el = l ++ el
他们都遇到了与此类似的错误:
Could not deduce (a' ~ [a'])
from the context (Functor f)
bound by the type signature for
_last :: Functor f => LensLike f [a] [a'] a a'
at editor.hs:22:10-27
‘a'’ is a rigid type variable bound by
the type signature for
_last :: Functor f => LensLike f [a] [a'] a a'
at editor.hs:22:10
Expected type: f [a']
Actual type: f a'
Relevant bindings include
f :: a -> f a' (bound at editor.hs:23:7)
_last :: LensLike f [a] [a'] a a' (bound at editor.hs:23:1)
In the second argument of ‘fmap’, namely ‘(f (last l))’
In the expression: (\ el -> (init l) ++ el) `fmap` (f (last l))
如何定义_last
镜头?
编辑: 这是构建的版本:
_last f l = (\el -> (init l) ++ [el]) `fmap`(f (last l))
不过,正如David/Daniel指出的那样,_last
应该是遍历,而不是镜头。
您在 el
周围缺少方括号((++)
需要一个包含两个参数的列表)。如果你把它们放进去,你的第一次尝试应该会成功。你的类型也太笼统了。 Haskell 中的列表不是异构的,因此它们只能包含一种类型的值。
此外,正如 Daniel Wagner 所说,这不可能是真实的镜头,因为它是局部的。您链接到的镜头文档已过时。当前的镜头库有 _last
as a Traversal
可以避免这个问题,因为 Traversal
可以有 0 个或多个目标,而镜头必须恰好有 1 个。