假设我有一个这样的数组: [1, 2, 3, 4]
如何使用镜头包仅修改偶数值?我正在寻找类似的东西:
filterLens even (+10) $ [1, 2, 3, 4]
=> [1, 12, 3, 14]
Run Code Online (Sandbox Code Playgroud) 该Traversable的论文给出了融合monoidal和一元遍历这听起来真的很有趣的18-19页上的一个例子,但我被他们的LaTex的混淆.
cciBody :: Char -> Count a
wciBody :: Char -> (|M| (State Bool) DotInASquare Count) a
Run Code Online (Sandbox Code Playgroud)
结果令人惊讶:
(traverse cciBody) xInACircle (traverse wciBody)
Run Code Online (Sandbox Code Playgroud)
是相同的:
traverse (cciBody xInACircle wciBody)
Run Code Online (Sandbox Code Playgroud)
我认为结果的类型是:
Count XInASquare (|M| (State Bool) DotInASquare Count) [a]
Run Code Online (Sandbox Code Playgroud)
但不是100%肯定.说话表情符号的人可以告诉我它应该如何看待Haskell吗?
我认为xInACircle可能是一个中缀sequenceA.类型匹配.或者也许它只是(,)一个实例Traversable.<*>即使结果看起来有点像,t (x <*> y) = t x <*> t y但它们在文章中没有使用Wingding,这绝对不是<*>.
xInACircle的类型是(Functor m,Functor n)⇒(a→mb)→(a→nb)→(a→(m XInASquare n)b).提醒你什么?不是我.
我正在阅读有关镜头的教程,在介绍中,作者lens通过展示我们如何使用标准Haskell实现OOP风格的"setter"/"getter"的一些示例来激发这一概念.我对以下示例感到困惑.
假设我们User根据图1(下面)定义代数数据类型.本教程(正确地)指出我们可以通过NaiveLens数据类型和nameLens函数实现"setter" 功能(也在图1中).图2给出了一个示例用法.
我很困惑为什么我们需要这样一个精心设计的构造(即NaiveLens数据类型和nameLens函数)来实现"setter"功能,当下面的(有点明显的)函数似乎同样很好地完成工作时:set' a s = s {name = a}.
但是,鉴于我的"显而易见"功能正是lambda函数的一部分nameLens,我怀疑使用下面的结构确实有一个优势,但我太密集了,看不出那个优点是什么.我希望其中一个Haskell向导可以帮助我理解.
图1(定义):
data User = User { name :: String
, age :: Int
} deriving Show
data NaiveLens s a = NaiveLens { view :: s -> a
, set :: a -> s -> s
}
nameLens :: NaiveLens User String
nameLens = NaiveLens name (\a s -> s …Run Code Online (Sandbox Code Playgroud) 考虑具有以下(伪)签名的"组合"函数:
(a1 -> a2 -> ... -> an -> r) ->
(s -> ai) ->
a1 -> a2 -> ... -> ai -> ... an -> r
where i in [1..n]
Run Code Online (Sandbox Code Playgroud)
当然我们不能在Haskell中编写上面的内容,但这是一个具体的例子:
f4change3 ::
(a1 -> a2 -> a3 -> a4 -> r) ->
(s -> a3) ->
a1 -> a2 -> s -> a4 -> r
f4change3 f g x1 x2 x3 x4 = f x1 x2 (g x3) x4
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,narity的每个函数都有一组函数n,因此我们需要的函数数量与arity呈二次方式增长.
我可以写出我需要的那些,但首先,我不想重新发明轮子,所以很高兴知道库是否已经完成了这个.但是,虽然我几乎没有使用镜头,但我已经阅读了一些关于它们的内容,这种问题似乎正好在他们的盟友身上,但我不确定该怎么做.如果可能的话,一些示例代码会很棒.
根据镜头教程:
type Getting b a b = (b -> Const b b) -> (a -> Const b a)
-- ... equivalent to: (b -> b ) -> (a -> b )
-- ... equivalent to: (a -> b )
Run Code Online (Sandbox Code Playgroud)
问题:为什么(b -> b) -> (a -> b)相当于(a -> b)?
如果我有一个嵌套记录的镜头,每个镜头返回一个Maybe,我怎么能让它们组成,所以如果"遍历"中的任何内容返回一个Nothing最后的结果是Nothing?
data Client = Client
{
clientProperties :: Maybe Properties
, ...
}
data Properties = Properties
{
propSmtpConfig :: Maybe SmtpConfig
, ...
}
c :: Client
c = undefined
smtp = c ^. (properties . smtpConfig) -- How to make these lenses compose?
Run Code Online (Sandbox Code Playgroud)
编辑我尝试了很多选项,但这是我能想到的最好的选择.寻找更清洁的东西:
(client ^. properties) >>= (view smtpConfig)
Run Code Online (Sandbox Code Playgroud) 这是我一直在处理的一些代码的版本,删除了细节.希望很清楚我正在尝试做什么,但如果没有,我可以澄清.我很擅长使用镜头,所涉及的复杂类型往往使它们看起来比它们的价值更麻烦.
-- some data type
type AType = ...
data Thing = Th { _v, _w, _x :: AType, _otherStuff :: ... }
makeLenses ''Thing
-- some operation that can be performed on corresponding x or w or v values in two Things.
f :: AType -> AType -> AType
f = ...
-- apply f to the corresponding v, and w, and x values in a and b; then store each result in the respective field of a, leaving …Run Code Online (Sandbox Code Playgroud) 我试图为多种类型创建一个多态镜头decleration(没有模板haskell).
module Sample where
import Control.Lens
data A = A {_value:: Int}
data B = B {_value:: Int}
data C = C {_value:: String}
value = lens _value (\i x -> i{_value=x}) -- <<< ERROR
Run Code Online (Sandbox Code Playgroud)
但我得到以下错误:
Ambiguous occurrence ‘_value’
It could refer to either the field ‘_value’,
defined at library/Sample.hs:5:13
or the field ‘_value’, defined at
library/Sample.hs:4:13
or the field ‘_value’, defined at
library/Sample.hs:3:13
|
6 | value = lens _value (\i x -> i{_value=x}) -- <<< ERROR
| ^^^^^^ …Run Code Online (Sandbox Code Playgroud) 假设你声明了两个同构
showing :: (Read a, Show a) => Iso' String a
showing = iso read show
reading :: (Read a, Show a) => Iso' a String
reading = iso show read
Run Code Online (Sandbox Code Playgroud)
它们是不安全的,并不是每个String都会解析为a.
这引出了一个问题:为什么这两个不包含在库enum = iso fromEnum toEnum中?
它同样不安全,不能通过类型系统来防止.他们都把负担转嫁给程序员,程序员必须确保转换不会破坏同构.
快速示例:under enum (+1) True将抛出异常
我有这些类型(还有更多):
data Player = PlayerOne | PlayerTwo deriving (Eq, Show, Read, Enum, Bounded)
data Point = Love | Fifteen | Thirty deriving (Eq, Show, Read, Enum, Bounded)
data PointsData =
PointsData { pointsToPlayerOne :: Point, pointsToPlayerTwo :: Point }
deriving (Eq, Show, Read)
Run Code Online (Sandbox Code Playgroud)
我正在做Tennis kata,作为实现的一部分,我想使用一些函数,这些函数使我能够为任意播放器获取或设置积分,只有在运行时才能知道。
正式地,我需要像这样的功能:
pointFor :: PointsData -> Player -> Point
pointFor pd PlayerOne = pointsToPlayerOne pd
pointFor pd PlayerTwo = pointsToPlayerTwo pd
pointTo :: PointsData -> Player -> Point -> PointsData
pointTo pd PlayerOne p …Run Code Online (Sandbox Code Playgroud)