我一直在说我的东西绊倒猜测是一个错误Data.Map,但也很可能在我的Haskell知识的错误.希望有人能澄清它是什么:)
请参考这个要点.我正在将循环链表结构序列化为字节流.对于任何给定节点,形式如下:
data Node = Node
{ val :: Word8
, next :: Node
}
Run Code Online (Sandbox Code Playgroud)
我希望它被序列化为一对字节:表示第一个字节val,第二个字节表示next可以定位的字节流中的偏移量.例如,我希望:
let n0 = Node 0 n1
n1 = Node 1 n0
Run Code Online (Sandbox Code Playgroud)
被序列化为[0, 1, 1, 0].没什么大不了.
这里稍微棘手的部分是我正在利用MonadFix实例RWST来"绑定"字节流偏移:我维护一个从节点到偏移的映射,在序列化期间填充映射,但也引用了映射中没有的映射必然存在,直到序列化完成.
当地图实现Data.HashMap.Lazy(来自无序容器)时,这非常有用.但是,当实现是通常的Data.Map(从容器)时,程序堆栈溢出 - 没有双关语意图 - Map尝试无限地比较两个节点使用(==).
所以我的问题是:这是一个错误Data.Map,或者我对这些结构在存在mfix缺陷时应该如何表现的假设?
在做一些简单的基准测试的过程中,我遇到了让我感到惊讶的事情.从Network.Socket.Splice获取此片段:
hSplice :: Int -> Handle -> Handle -> IO ()
hSplice len s t = do
a <- mallocBytes len :: IO (Ptr Word8)
finally
(forever $! do
bytes <- hGetBufSome s a len
if bytes > 0
then hPutBuf t a bytes
else throwRecv0)
(free a)
Run Code Online (Sandbox Code Playgroud)
人们预计,hGetBufSome并hPutBuf在这里就不需要分配内存,因为它们写进去,并从预分配的缓冲区读取.该文件似乎支持这一直觉了......但很可惜:
individual inherited
COST CENTRE %time %alloc %time %alloc bytes
hSplice 0.5 0.0 38.1 61.1 3792
hPutBuf 0.4 1.0 19.8 29.9 12800000
hPutBuf' 0.4 …Run Code Online (Sandbox Code Playgroud) 本Collections类有很多的静态辅助方法来提供只读视图各种集合类型,例如unmodifiableSet(),unmodifiableList()等等.对于这些视图对象中,hashCode()和equals()方法前调用底层集合......随着一个奇怪的例外:unmodifiableCollection().
JavaDoc 明确指出:
返回的集合并没有将hashCode并传递给底层集合等于操作,但依靠
Object的equals和hashCode方法.在后备集合是集合或列表的情况下,这对于保留这些操作的合同是必要的.
我的问题:wtf是这个在谈论?如果支持集合是集合或列表,我希望行为与unmodifiableSet()和一致unmodifiableList().怎么会违反hashCode/equals合约?
在编写简单的RPN计算器的过程中,我有以下类型的别名:
type Stack = List[Double]
type Operation = Stack => Option[Stack]
Run Code Online (Sandbox Code Playgroud)
...我写了一个好奇的Scala代码:
val newStack = operations.foldLeft(Option(stack)) { _ flatMap _ }
Run Code Online (Sandbox Code Playgroud)
这将获取stack值的初始值并应用operations该堆栈的列表.每个操作都可能失败(即产生一个Option[Stack]),所以我对它们进行排序flatMap.对我来说有些不同寻常的事情(在我看来)是我折叠了一系列monadic函数,而不是折叠数据列表.
我想知道是否有一个标准函数可以捕获这种"折叠绑定"行为.当我试图玩"Name That Combinator"游戏时,Hoogle通常是我的朋友,所以我在Haskell尝试了相同的心理锻炼:
foldl (>>=) (Just stack) operations
Run Code Online (Sandbox Code Playgroud)
这里的类型是:
foldl :: (a -> b -> a) -> a -> [b] -> a
(>>=) :: Monad m => m a -> (a -> m b) -> m b
Run Code Online (Sandbox Code Playgroud)
所以我的神秘foldl (>>=)组合器的类型,在制作类型foldl和(>>=)排队之后,应该是:
mysteryCombinator :: Monad m => …Run Code Online (Sandbox Code Playgroud) 我想写一个光滑的代码(通过打结来节省我很多时间来实现).它大致是这样的,
n <- myinstr n x
Run Code Online (Sandbox Code Playgroud)
在理论上,myinstr应该运行x以获得一个价值,这将成为n.myinstr在Statemonad 中运行,将n进入状态,但这不会影响x计算.
我尝试过使用DoRec和实现的mfix,
instance Monad => MonadFix (MyMonad ) where
mfix f = fix (\mx -> mx >>= f)
Run Code Online (Sandbox Code Playgroud)
事情冻结了.有没有任何方法可以修复我的代码(或者第一次正确设计它的方法),还是应该写一些更直接的东西?
我有一个问题,我不知道如何推理.我只是想问一下是否有人可以帮助我解决具体问题,但我突然意识到我可以提出一个更普遍的问题,希望能得到一个更好的一般性理解.希望.所以这里:
当你的程序太懒,通常很明显,因为你最终会遇到像空间泄漏这样的明显问题.我有相反的问题:我的程序太严格了.我想扎 结,并发现某些事情,我试图这样做会以某种方式打败我需要的懒惰.所以我的一般问题是,如何调试不必要的严格性?
为了完整起见,这是我的具体情况:我在RWS,编写器组件填充地图,阅读器组件观察该地图的最终状态.在我完成填充之前,我不能对这张地图做任何严格的事情.在地图中查找值似乎没有问题,例如:
do
m <- ask
val <- m ! key
doSomething val -- etc.
Run Code Online (Sandbox Code Playgroud)
但是(!)没有使用error,我更愿意使用我的monad失败fail.所以我想做类似以下的事情:
do
m <- ask
maybe
(fail "oh noes")
(doSomething)
(lookup key m)
Run Code Online (Sandbox Code Playgroud)
这导致我的程序<<loop>>,我不明白.在我看来,这不应该比使用更严格(!),但显然我错了......
假设我有一个像这样的愚蠢的小案例类:
case class Foo(name: String, other: Foo)
Run Code Online (Sandbox Code Playgroud)
我如何定义a和b不可改变这样a.other的b,而且b.other是a?scala是否提供了"打结"的方法?我想做这样的事情:
val (a, b): (Foo, Foo) = (Foo("a", b), Foo("b", a)) // Doesn't work.
Run Code Online (Sandbox Code Playgroud)
可能性
在Haskell中,我会这样做:
data Foo = Foo { name :: String, other :: Foo }
a = Foo "a" b
b = Foo "b" a
Run Code Online (Sandbox Code Playgroud)
绑定到a和b包含在同一let表达式中或顶层的绑定.
或者,在不滥用Haskell的自动化letrec功能的情况下:
(a, b) = fix (\ ~(a', b') -> Foo "a" b', Foo "b" …Run Code Online (Sandbox Code Playgroud) 我想做以下事情:
public class ImmutableList<T> {
public <U super T> ImmutableList<U> add(U element) { ... }
}
Run Code Online (Sandbox Code Playgroud)
也就是说,给定一个不可变列表T,你可以U在列表中添加任何一个以产生一个不可变列表U,其约束U必须是一个超类型T.例如
Object(假设岩石和原始人不共享其他共同的祖先).这在理论上听起来很棒,但是U根据JLS ,下限是不合法的.我可以写:
public class ImmutableList<T> {
public ImmutableList<T> add(T element) { ... }
public static <U> ImmutableList<U> add(ImmutableList<? extends U> list, U element) { ... }
}
Run Code Online (Sandbox Code Playgroud)
以这种方式,编译器将正确地推断列表的元素类型和U我们想要添加的最小上限.这是合法的.它也很糟糕.相比:
// if 'U super T' were legal
list.add(monkey).add(human).add(rock);
// assuming 'import static ImmutableList.add'
add(add(add(list, …Run Code Online (Sandbox Code Playgroud) 似乎Scala的显式类型自引用最常见的用法是" Cake模式 ",其中模块的依赖项声明如下:
class Foo { this: A with B with C =>
// ...
}
Run Code Online (Sandbox Code Playgroud)
通常,暂时忽略蛋糕模式A,B并且C可以引用任何类型级别的东西,例如类型参数:
class Outer[A, B, C] {
class Inner { this: A with B with C =>
// ...
}
}
Run Code Online (Sandbox Code Playgroud)
......或抽象类型的成员:
class Outer {
type A
type B
type C
class Inner { this: A with B with C =>
// ...
}
}
Run Code Online (Sandbox Code Playgroud)
在这些情况中,我们都不能写abstract class Inner extends A with B with C …
查看文档Control.Applicative,我注意到它们具有某些monad的实例声明(例如IO,Maybe特别是ST),但是没有MTL monad的实例,例如State和RWS.相反,它看起来像是WrappedMonad定义了一个通用类型,我猜测它是涵盖所有其他情况.
所以这是我的问题:
为什么没有ApplicativeMTL monad的实例?到目前为止,我自己能够找到的最好的答案是一个三年前的帖子,有人实现了这些实例,并被忽略了.
最终我希望能够以State一种适用的方式使用(如我所推荐的那样),但如果我不得不用WrappedMonad数据构造函数丢弃我的代码,那么它似乎不是一个胜利.我也可以不理会WrappedMonad完全,并定义Applicative实例自己,是为做了同样的方式IO,ST等等:在以下方面return与ap......但似乎愚蠢的为好.
我想用System.Random.MWC.Monad中的 Rand monad生成无限的数字流.如果只有这个monad的MonadFix实例,或者像这样的实例:
instance (PrimMonad m) => MonadFix m where
...
Run Code Online (Sandbox Code Playgroud)
然后人们可以写:
runWithSystemRandom (mfix (\ xs -> uniform >>= \x -> return (x:xs)))
Run Code Online (Sandbox Code Playgroud)
虽然没有一个.
我正在浏览MonadFix文档,但我没有看到实现此实例的明显方法.
haskell ×8
monadfix ×4
scala ×3
java ×2
monads ×2
applicative ×1
cake-pattern ×1
collections ×1
combinators ×1
containers ×1
generics ×1
io ×1
letrec ×1
lower-bound ×1
profiling ×1
random ×1
state-monad ×1
strictness ×1
typeclass ×1
unmodifiable ×1