我经常在Haskell代码中找到这种模式:
options :: MVar OptionRecord
options = unsafePerformIO $ newEmptyMVar
...
doSomething :: Foo -> Bar
doSomething = unsafePerformIO $ do
opt <- readMVar options
doSomething' where ...
Run Code Online (Sandbox Code Playgroud)
基本上,一个人有一个选项或类似的记录,最初是在程序开始时设置的.由于程序员很懒惰,他不想options在整个程序中携带记录.他定义了一个MVar保持它 - 由丑陋的使用定义unsafePerformIO.程序员确保状态只设置一次,并且在任何操作发生之前.现在程序的每个部分都必须unsafePerformIO再次使用,只是为了提取选项.
在我看来,这样的变量被认为是实用的纯粹(不要打败我).是否有一个库抽象出这个概念,并确保变量只设置一次,即在初始化之前没有调用,并且不需要写unsafeFireZeMissilesAndMakeYourCodeUglyAnd DisgustingBecauseOfThisLongFunctionName
haskell global-variables purely-functional unsafe-perform-io
我希望有人可以对Data.Reflection中的黑魔法有所了解.相关片段是:
{-# LANGUAGE CPP #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE KindSignatures #-}
module Data.Reflection
(
Reifies(..)
, reify
) where
import Data.Proxy
import Unsafe.Coerce
class Reifies s a | s -> a where
-- | Recover a value inside a 'reify' context, given a proxy for its
-- reified type.
reflect :: proxy s -> a
newtype Magic a r = Magic (forall …Run Code Online (Sandbox Code Playgroud) 这里有一个基本的monad问题,与Repa无关,还有几个与Repa有关的问题.
我正在使用Repa3工作.我无法获得高效的并行代码.如果我让我的函数返回延迟数组,我会得到极其缓慢的代码,可以很好地扩展到8个内核.该代码每GHC探测器占用超过20GB的内存,并且比基本的Haskell未装箱矢量运行几个数量级.
或者,如果我让所有函数返回Unboxed清单数组(仍然尝试在函数中使用fusion,例如当我执行'map')时,我获得了更快的代码(仍然比使用Haskell未装箱的向量慢)根本没有扩展,实际上随着核心数量的增加会略微变慢.
基于Repa-Algorithms中的FFT示例代码,似乎正确的方法是始终返回清单数组.有没有我应该返回延迟数组的情况?
FFT代码也充分利用了'now'功能.但是,当我尝试在我的代码中使用它时,我收到类型错误:
type Arr t r = Array t DIM1 r
data CycRingRepa m r = CRTBasis (Arr U r)
| PowBasis (Arr U r)
fromArray :: forall m r t. (BaseRing m r, Unbox r, Repr t r) => Arr t r -> CycRingRepa m r
fromArray =
let mval = reflectNum (Proxy::Proxy m)
in \x ->
let sh:.n = extent x
in assert (mval == 2*n) PowBasis $ now $ computeUnboxedP $ bitrev x
Run Code Online (Sandbox Code Playgroud)
没有'now',代码编译得很好.使用'now',我收到以下错误: …
在将代码迭代到正确的版本时,我遇到了以下好奇心:
{-# LANGUAGE RankNTypes #-}
module Foo where
import Data.Vector.Generic.Mutable as M
import Control.Monad.Primitive
-- an in-place vector function with dimension
data DimFun v m r =
DimFun Int (v (PrimState m) r -> m ())
eval :: (PrimMonad m, MVector v r) => DimFun v m r -> v (PrimState m) r -> m ()
eval = error ""
iterateFunc :: (PrimMonad m, MVector v r)
=> (forall v' . (MVector v' r) => DimFun v' m r) -> …Run Code Online (Sandbox Code Playgroud) 我试图理解为什么这个代码的一个版本编译,而一个版本没有.
{-# LANGUAGE RankNTypes, FlexibleContexts #-}
module Foo where
import Data.Vector.Generic.Mutable as M
import Data.Vector.Generic as V
import Control.Monad.ST
import Control.Monad.Primitive
data DimFun v m r =
DimFun {dim::Int, func :: v (PrimState m) r -> m ()}
runFun1 :: (Vector v r, MVector (Mutable v) r) =>
(forall m . (PrimMonad m) => DimFun (Mutable v) m r) -> v r -> v r
runFun1 (DimFun dim t) x | V.length x == dim = runST $ do
y …Run Code Online (Sandbox Code Playgroud) 我有一个类Cyc c r,它具有表单数据的功能c m r,其中m是一个幻像类型.例如,
class Cyc c r where
cyc :: (Foo m, Foo m') => c m r -> c m' r
Run Code Online (Sandbox Code Playgroud)
我没有做出m类参数的充分理由.出于此示例的目的,主要原因是它减少了对函数的约束数量.在我的实际例子中,对这个界面更迫切的需求是我使用更改和隐藏的幻像类型,所以这个界面让我得到Cyc任何幻像类型的约束.
这个选择的一个缺点是我不能制作Num (c m r)超类约束Cyc.我的意图是c m r应该Num随时随地(Cyc c r, Foo m).目前的解决方案非常烦人:我在课堂上添加了方法Cyc
witNum :: (Foo m) => c m r -> Dict (Num (c m r))
Run Code Online (Sandbox Code Playgroud)
哪种方式完成同样的事情.现在,当我有一个带有泛型Cyc并需要Num (c m r)约束的函数时,我可以写:
foo :: …Run Code Online (Sandbox Code Playgroud) 这是代码:
{-# LANGUAGE FlexibleContexts #-}
import Data.Int
import qualified Data.Vector.Unboxed as U
import qualified Data.Vector.Generic as V
{-# NOINLINE f #-} -- Note the 'NO'
--f :: (Num r, V.Vector v r) => v r -> v r -> v r
--f :: (V.Vector v Int64) => v Int64 -> v Int64 -> v Int64
--f :: (U.Unbox r, Num r) => U.Vector r -> U.Vector r -> U.Vector r
f :: U.Vector Int64 -> U.Vector Int64 -> U.Vector Int64 …Run Code Online (Sandbox Code Playgroud) 这是我的代码:
{-# LANGUAGE TypeFamilies, TypeOperators, DataKinds, PolyKinds, FlexibleContexts, UndecidableInstances #-}
module Foo where
import Data.Singletons.Prelude
import Data.Type.Equality
data TP a b
-- foldl (\(bool, r) x -> (bool && (r == x), r)) (True, head xs) xs
type family Same (b :: Bool) (r :: k) (rq :: [k]) :: k where
Same bool r (x ': xs) = Same (bool :&& (r == x)) r xs
Same bool r '[] = TP bool r
data NotEqualFailure
-- converts a …Run Code Online (Sandbox Code Playgroud) 我试图拉值超出一个单子,但保留值,它不依赖于单子,多态.特别:
foo :: (Monad mon, Ring a) => mon a
foo = return 3
main :: IO ()
main = do
x <- foo
print (x :: Double)
print (x :: Int)
Run Code Online (Sandbox Code Playgroud)
关键是计算的monadic部分计算起来很昂贵,所以我只想做一次,同时保持monad多态的值.到目前为止我的所有尝试:
x签名forall a. (Ring a) => a)foo :: (Monad mon) => mon (forall a . (Ring a) => a) -XNoMonomorphismRestriction和NoMonoLocalBins 对于不能使用的impregicative polymorphism,或者没有工作或给出错误.是否有某种方法可以在没有不可预测的多态性的情况下从monad中提取多态值(或者:在GHC中是否有一种安全的方法来使用impredicative polymorphism)?
设置:我有一个Haskell库HLib,可以调用C/C++后端CLib来提高效率.后端很小,专门用于HLib.的接口CLib将仅被通过暴露HLib; HLib测试,HLib基准测试和第三方库依赖于HLib不会直接进行FFI调用CLib.从测试/基准/第三方lib的角度来看,HLib应该是纯粹的Haskell.这意味着在,例如小集团文件部分,HLib测试,应该有任何引用-lCLib,libCLib等等,只有build-depends上HLib,并且可执行文件不应该需要寻找一个动态CLib库.我需要能够构建和运行HLib第三方库中的所有可执行文件,以及运行cabal repl开发.
最初,CLib写于纯C.卡瓦尔具有用于这种情况下的支持,并且我可以集成CLib到HLib在精确地,通过使用上面描述的方式include-dirs,c-sources和includes在小集团文件字段.
CLib已经发展成为一个C++库,我无法弄清楚如何让cabal轻松集成.相反,我使用自定义构建和Setup.hs的makefile,就像这样.你可以在这里看到这个方法的一个小例子1,2.
在那个例子中,我无法运行cabal repl,HLib因为"加载档案不受支持".这实际上意味着我需要一个动态C++库,它很容易创建(在CLibmakefile中有一个注释行来完成它).但是,如果我确实创建了动态C++库,那么HLib由于"没有这样的文件或目录libclib.so" ,测试会在运行时失败.这很糟糕(除了崩溃),因为测试可执行文件链接到动态库,这不是我想要的.
具体来说,测试HLib和SimpleLib应该通过,我应该能够cabal repl在 …
haskell ×10
ghc ×6
cabal ×1
lambda ×1
monads ×1
performance ×1
pointfree ×1
profiling ×1
reflection ×1
repa ×1