来自GHC 7.6 的文档:
[Y]你通常甚至不需要SPECIALIZE pragma.在编译模块M时,GHC的优化器(带-O)自动考虑在M中声明的每个顶级重载函数,并将其专门用于在M中调用它的不同类型.优化器还考虑每个导入的INLINABLE重载函数,并将其专门用于M中调用的不同类型.
和
此外,给定函数f的SPECIALIZE编译指示,GHC将自动为f调用的任何类型类重载函数创建特殊化,如果它们与SPECIALIZE编译指示位于同一模块中,或者它们是INLINABLE; 等等,过渡性的.
因此GHC应该自动专门化一些INLINABLE
没有编译指示标记的/大多数/所有(?)函数,如果我使用显式编译指示,则特化是可传递的.我的问题是:auto -specialization 是否具有传递性?
具体来说,这是一个小例子:
Main.hs:
import Data.Vector.Unboxed as U
import Foo
main =
let y = Bar $ Qux $ U.replicate 11221184 0 :: Foo (Qux Int)
(Bar (Qux ans)) = iterate (plus y) y !! 100
in putStr $ show $ foldl1' (*) ans
Run Code Online (Sandbox Code Playgroud)
Foo.hs:
module Foo (Qux(..), Foo(..), plus) where
import Data.Vector.Unboxed as U
newtype Qux r = Qux (Vector r)
-- …
Run Code Online (Sandbox Code Playgroud) 这是场景:我已经编写了一些带有类型签名的代码,并且GHC抱怨无法推断x~y某些x
和y
.你通常可以将GHC作为一个骨骼并简单地将同构函数添加到函数约束中,但这有几个原因:
我只花了几个小时与案例3作斗争.我正在玩syntactic-2.0
,我试图定义一个与域无关的版本share
,类似于在中定义的版本NanoFeldspar.hs
.
我有这个:
{-# LANGUAGE GADTs, FlexibleContexts, TypeOperators #-}
import Data.Syntactic
-- Based on NanoFeldspar.hs
data Let a where
Let :: Let (a :-> (a -> b) :-> Full b)
share :: (Let :<: sup,
Domain a ~ sup,
Domain b ~ sup,
SyntacticN (a -> (a -> b) -> b) fi)
=> a -> (a -> b) -> a
share = sugarSym Let
Run Code Online (Sandbox Code Playgroud)
和GHC could not …
我最近发布了一个问题,关于句法2.0有关的定义share
.我在GHC 7.6中有这个工作:
{-# LANGUAGE GADTs, TypeOperators, FlexibleContexts #-}
import Data.Syntactic
import Data.Syntactic.Sugar.BindingT
data Let a where
Let :: Let (a :-> (a -> b) :-> Full b)
share :: (Let :<: sup,
sup ~ Domain b, sup ~ Domain a,
Syntactic a, Syntactic b,
Syntactic (a -> b),
SyntacticN (a -> (a -> b) -> b)
fi)
=> a -> (a -> b) -> b
share = sugarSym Let
Run Code Online (Sandbox Code Playgroud)
但是,GHC 7.8希望-XAllowAmbiguousTypes …
我遇到了让GHC专门化一个具有类约束的函数的问题.我有我的问题就在这里的一个小例子:Foo.hs和 Main.hs.这两个文件编译(GHC 7.6.2,ghc -O3 Main
)并运行.
注意:
Foo.hs
真的被剥离了.如果您想了解为什么需要约束,可以在这里看到更多代码.如果我将代码放在一个文件中或进行许多其他微小的更改,GHC只是简单地将调用内联到plusFastCyc
.这不会发生在实际代码中,因为plusFastCyc
GHC内联太大,即使在标记时也是如此INLINE
.关键是要专门调用plusFastCyc
,而不是内联它.plusFastCyc
在真实代码的许多地方被调用,所以即使我可以强迫GHC这样做,也不可能复制这么大的功能.
感兴趣的代码是plusFastCyc
in Foo.hs
,在这里转载:
{-# INLINEABLE plusFastCyc #-}
{-# SPECIALIZE plusFastCyc ::
forall m . (Factored m Int) =>
(FastCyc (VT U.Vector m) Int) ->
(FastCyc (VT U.Vector m) Int) ->
(FastCyc (VT U.Vector m) Int) #-}
-- Although the next specialization makes `fcTest` fast,
-- it isn't useful to me in …
Run Code Online (Sandbox Code Playgroud) 我有这个代码:
class SymbolSet tpe where
data Symbol tpe :: *
data SSet tpe where
Identity :: tpe -> SSet tpe
And :: SSet tpe -> Symbol tpe -> SSet tpe
class HasElem a b where
instance (SymbolSet tpe) => HasElem (And (Identity tpe) s) s
instance (HasElem sset s) => HasElem (And sset s) s
Run Code Online (Sandbox Code Playgroud)
这是在GHC-7.4中编译的.但是,在转向GHC-7.6时,它开始出现编译错误:
'And' of tpe `forall tpe. tpe -> Symbol * tpe -> SSet tpe' is not promotable
Run Code Online (Sandbox Code Playgroud)
在挖掘文档时,我发现在GHC-7.6与GHC-7.4的 "数据类型升级"页面中添加了一个新的条款
我们不会提升其构造函数是多态的,涉及约束或使用存在量化的数据类型.
我的问题是:
你如何设计和构建你的monadic堆栈?我第一次需要构建一个monadic堆栈(使用变换器)来解决现实问题,但我并不完全确定堆叠变换器的顺序.如你所知,只要计算有点* -> *
,基本上任何东西都可以在变换器中扮演内部monad的角色,因此有几个问题:
lift . lift . liftIO [...]
?我的直觉是,如果变形金刚得到一些实例(例如MonadReader,MonadIO等,就像大多数变形金刚mtl
一样),那么放置变压器的顺序并不重要.我有兴趣听取经验丰富的Haskellers关于最佳实践或经验法则的意见.
forever $ print "Thanks!"
一个.
在关于DSL的无标记最终解释器的这些非常酷的注释的第2.3节中,Oleg Kiselyov展示了如何解决一次解析序列化DSL表达式并多次解释它的问题.
简而言之,他用类型表明了"伪造的一流多态"
newtype Wrapped = Wrapped (? repr. ExpSYM repr ? repr)
fromTree :: String ? Either ErrMsg Wrapped
Run Code Online (Sandbox Code Playgroud)
不令人满意,因为它是不可扩展的:我们必须有不同的Wrapper
/ fromTree
为每个组上的约束repr
.因此,我倾向于使用他的复制器解释器的解决方案.这个问题是关于如何使用HOAS的解释器.
具体来说,请考虑以下语言进行目标语言绑定:
class Lam repr where
lam :: (repr a -> repr b) -> repr (a -> b)
app :: repr (a -> b) -> repr a -> repr b
Run Code Online (Sandbox Code Playgroud)
我在为复制器解释器提供类的声音实例时遇到了麻烦Lam
.这就是我所拥有的:
data Dup repr1 repr2 a = Dup {unDupA :: …
Run Code Online (Sandbox Code Playgroud) 以下代码段编译:
{-# LANGUAGE TypeFamilies #-}
type family Foo a b
f :: (Foo a b ~ Int) => a -> b -> b
f = error ""
Run Code Online (Sandbox Code Playgroud)
但是中缀类型操作符似乎表现不同:
{-# LANGUAGE TypeFamilies #-}
type family a \\ b
f :: (a \\ b ~ Int) => a -> b -> b
f = error ""
Run Code Online (Sandbox Code Playgroud)
GHC抱怨第二个论点\\
应该是善意的*
,但是b ~ Int
有点善意Constraint
.当然这可以用parens修复,但我想知道是否还有另一种方法.
我试过设置我的运营商与固定性声明的优先级infixl 9 \\
,但这并不解决问题,这表明的优先级~
是至少9(如果我解释是正确的).我尝试使用这个答案中的技巧让GHCi告诉我优先级~
,但它没有用. …
我经常在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)