我想过滤遍历,然后选择要使用的最后一个元素over.
像这样的东西(但实际上会编译):
[1,2,3,4] & traverse . filtered even . _last +~ 10
> [1,2,3,14]
Run Code Online (Sandbox Code Playgroud)
有任何想法吗?
PS我知道filtered只有在不影响遍历中的元素数量时才有效.
我正在执行的实际用例是仅选择uniplate与某个谓词匹配的递归遍历的最低级别; 如果你对如何做到这一点有其他想法,我很乐意听到它们!
我有一个谜题,
我设法编写了一些使用递归方案来做这些事情的代码,但它非常混乱,这通常意味着我在某个地方错过了一个有用的抽象.
我正在为我的文本编辑器设计一个布局系统
Rasa; 它使用与Vim非常相似的方式进行拆分.我决定使用树来描述分裂; 您可以将它想象为垂直或水平分割的二叉树,在叶节点处具有"视图".这张照片
可能有帮助.
这是我的初始数据结构:
data Direction = Hor | Vert
data Tree a =
Branch Direction (Tree a) (Tree a)
| Leaf a
deriving (Functor)
Run Code Online (Sandbox Code Playgroud)
我需要的一些操作是:
split :: (View -> Tree View) -> Tree View -> Tree View
将节点(或不是)水平或垂直地分成两个节点(同时保持它们在树中的位置)close :: (View -> Bool) -> Tree View -> Tree View 通过从树中删除它们并正确地重新组织相邻视图来"关闭"与谓词匹配的任何视图.fmap; 我希望树能成为一个仿函数,所以我可以改变观点.一些很好的功能: - focusRight :: Tree View -> Tree View,当且仅当左边最近的水平连接视图WAS处于活动状态时,才将视图设置为活动状态
我正在寻找一个抽象或一组抽象,以一种干净的方式提供这种功能.到目前为止,这是我的思考过程:
起初我以为我有一个Monoid,标识是空树,
mappend只是将另一个分支附加到树上,但这不起作用,因为我有两个操作:垂直追加和水平追加,操作不是关联的当他们混在一起的时候.
接下来我想'我的一些操作取决于他们的背景'所以我可能有一个Comonad.我拥有的树的版本不能作为共同monad工作,因为我没有extract分支上的值,所以我重构了我的树,如下所示:
data Tree a …Run Code Online (Sandbox Code Playgroud) 我有一个棘手的问题;
所以,我知道GHC将"缓存"(缺乏一个更好的术语)顶级定义,只计算一次,例如:
myList :: [Int]
myList = fmap (*10) [0..10]
Run Code Online (Sandbox Code Playgroud)
即使我myList在几个地方使用,GHC注意到该值没有参数,因此它可以共享它并且不会"重建"列表.
我想这样做,但计算依赖于类型级上下文; 一个简单的例子是:
dependentList :: forall n. (KnownNat n) => [Nat]
dependentList = [0..natVal (Proxy @n)]
Run Code Online (Sandbox Code Playgroud)
所以有趣的是,没有'单一'可缓存值dependentList; 但是一旦应用了一种类型,它就减少到一个常数,所以理论上一旦类型检查器运行,GHC就会认识到几个点都依赖于"相同" dependentList; 例如(使用TypeApplications)
main = do
print (dependentList @5)
print (dependentList @10)
print (dependentList @5)
Run Code Online (Sandbox Code Playgroud)
我的问题是,GHC会认识到它可以共享这两个5列表吗?或者它是分别计算每一个?从技术上讲,甚至可以在编译时而不是运行时计算这些值,是否有可能让GHC这样做?
我的情况稍微复杂一些,但是应该遵循与示例相同的约束,但是我的类似dependentList值是计算密集的.
如果能让事情成为可能,我完全不反对使用类型类来做这件事; GHC缓存并重用类型词典吗?也许我可以把它变成类型类词典中的常量来获取缓存?
想法有人吗?或者有人读过我看看这是如何工作的?
我更喜欢这样做,编译器可以解决它而不是使用手动memoization,但我愿意接受:)
谢谢你的时间!
对于简单的函数组合,是否有"do notation"语法糖?
(即(.) :: (b -> c) -> (a -> b) -> a -> c)
我希望能够存储一些成分的结果供以后使用(同时仍然继续链.
如果可能的话,我宁愿不使用RebindableSyntax扩展.
我正在寻找这样的东西:
composed :: [String] -> [String]
composed = do
fmap (++ "!!!")
maxLength <- maximum . fmap length
filter ((== maxLength) . length)
composed ["alice", "bob", "david"]
-- outputs: ["alice!!!", "david!!!"]
Run Code Online (Sandbox Code Playgroud)
我不确定这样的事情是否可能,因为早期函数的结果基本上必须通过"通过"maxLength的绑定,但我愿意听到任何其他类似的表达选项.基本上我需要收集信息,因为我通过合成以便以后使用它.
也许我可以用状态monad做这样的事情?
谢谢你的帮助!
编辑
这种事情有点起作用:
split :: (a -> b) -> (b -> a -> c) -> a -> c
split ab bac a = bac (ab a) a
composed …Run Code Online (Sandbox Code Playgroud) 仍在我的文本编辑器Rasa上工作。
目前,我正在构建用于跟踪视口/拆分的系统(类似于vim拆分)。对我来说,将这种结构表示为一棵树似乎很自然:
data Dir = Hor
| Vert
deriving (Show)
data Window a =
Split Dir SplitInfo (Window a) (Window a)
| Single ViewInfo a
deriving (Show, Functor, Traversable, Foldable)
Run Code Online (Sandbox Code Playgroud)
效果很好,我将Views 存储在树中,然后可以在它们上遍历/ fmap来更改它们,这也与镜头包很好地吻合!
我最近一直在学习递归方案,这似乎是一个合适的用例,因为树是递归的数据结构。
我设法弄清楚了,以构建Fixpoint版本:
data WindowF a r =
Split Dir SplitInfo r r
| Single ViewInfo a
deriving (Show, Functor)
type Window a = Fix (WindowF a)
Run Code Online (Sandbox Code Playgroud)
但是,现在Functor实例已被r; 用尽。
我尝试了几种
deriving instance Functor Window
Run Code Online (Sandbox Code Playgroud)
但是它很令人吃惊,因为window是类型的同义词。
和:
newtype Window a = …Run Code Online (Sandbox Code Playgroud) haskell functor recursive-datastructures recursion-schemes fixpoint-combinators
这是这个问题的一个更具体的变体:Mutate only focus of Store Comonad?,以免一次问多个问题。
是否有任何与Control.Lens兼容的镜头允许我与 comonad 的焦点(来自 的值extract)或 Store Comonad ( pos)的索引/值进行交互?
似乎镜头在这里可能有用,但我一直找不到适合的东西;任何帮助将不胜感激,谢谢!
所以我最近一直在尝试固定点,并最终通过常规固定点的努力发现了一些用途;现在我正在转向共生不动点,我担心我已经陷入困境了;
以下是我尝试过的以及有效/无效的一些示例:
{-# language DeriveFunctor #-}
{-# language FlexibleInstances #-}
module WFix where
import Control.Comonad
import Control.Comonad.Cofree
import Control.Monad.Fix
Run Code Online (Sandbox Code Playgroud)
所以我从勒布定理开始列出;列表中的每个元素都是一个函数,它使用最终结果来计算其答案;这让我可以进行“电子表格”计算,其中值可以依赖于其他值。
spreadSheetFix :: [Int]
spreadSheetFix = fix $ \result -> [length result, (result !! 0) * 10, (result !! 1) + 1, sum (take 3 result)]
Run Code Online (Sandbox Code Playgroud)
好的,我已经完成了基本的修复工作,是时候继续讨论 comonad 类型了!以下是一些简单的 comonad 示例:
data Stream a = S a (Stream a)
deriving (Eq, Show, Functor)
next :: Stream a -> Stream a
next (S _ s) = s
instance Comonad Stream where
extract …Run Code Online (Sandbox Code Playgroud) 因此,我经常发现自己设计的"管道"就像数据流一样,并且通常最终导致管道本身是动态的.
有没有一种简单的方法可以做这样的事情?
pipe :: [a -> a] -> a -> a
Run Code Online (Sandbox Code Playgroud)
或者是否有一种不同的模式我应该用这样的东西来达成?它类似于State monad,但我不想编辑函数(a -> (), a)或其他:/
我意识到这是一个幺半群,所以我写了这个,这似乎是一个优雅的解决方案,它存在于某个库的某个库中吗?似乎大多数箭头和函数Monoids做不同的事情.
newtype Comp a = Comp {
runComp :: a -> a
}
instance Monoid (Comp a) where
(Comp a) `mappend` (Comp b) = Comp (b . a)
mempty = Comp id
pipe :: [a -> a] -> a -> a
pipe = runComp . foldMap Comp
Run Code Online (Sandbox Code Playgroud)
任何人都有他们用于此类事情的模式吗?谢谢!
我对Haskell很新,但我很喜欢学习它,它与我以前用过的所有东西都有所不同.我在Monads上读了一两本书以及它们如何影响流量,但是我仍然有点麻烦.为了更好,我正在努力解决代码问题的优秀问题,现在我遇到问题2,我已经在下面发布了我的代码,它运行正常,但感觉不尽如人意.
具体来说,我想知道如何清理这个:
main = getContents >>= (return . sum . (fmap getSquareFootage) . lines) >>= print
我不喜欢混合函数组合和fmap AND这样>>=的行,我觉得很难读.是否有更惯用的方法来实现相同的结果?我也对任何和所有Haskell风格的建议持开放态度,我真的没有人可以谈论这个,谢谢!
TLDR; 我怎么能惯用地组合fmap,.和>>=?
import Data.List.Split (splitOn)
main :: IO ()
main = getContents >>= (return . sum . (fmap getSquareFootage) . lines) >>= print
getSquareFootage :: String -> Int
getSquareFootage box = area dims + slack dims
where dims = read <$> splitOn "x" box
slack = minimum . sides
sides [l, w, h] = …Run Code Online (Sandbox Code Playgroud) haskell ×9
comonad ×3
composition ×2
haskell-lens ×2
caching ×1
do-notation ×1
functor ×1
ghc ×1
monads ×1
monoids ×1
optimization ×1
performance ×1