所以我理解类型的基本代数解释:
Either a b ~ a + b
(a, b) ~ a * b
a -> b ~ b^a
() ~ 1
Void ~ 0 -- from Data.Void
Run Code Online (Sandbox Code Playgroud)
......并且这些关系对于具体类型是正确的,例如Bool,与多态类型相反a.我还知道如何通过根据以下同构转换Church编码,将具有多态类型的类型签名转换为具体类型表示:
(forall r . (a -> r) -> r) ~ a
Run Code Online (Sandbox Code Playgroud)
所以,如果我有:
id :: forall a . a -> a
Run Code Online (Sandbox Code Playgroud)
我知道这并不意味着id ~ a^a,但它实际上意味着:
id :: forall a . (() -> a) -> a
id ~ ()
~ 1
Run Code Online (Sandbox Code Playgroud)
同理:
pair :: forall r . (a -> …Run Code Online (Sandbox Code Playgroud) ghc如果整数文字超出给定类型的范围,则最新版本将警告您.例如:
$ ghci
>>> let x = 330492039485 :: Data.Word.Word8
<interactive>:2:9: Warning:
Literal 330492039485 is out of the GHC.Word.Word8 range 0..255
Run Code Online (Sandbox Code Playgroud)
但是,ghc不会警告Data.Word类型的负数字文字.相反,它下溢(故意,根据文档):
>>> let x = -1 :: Data.Word.Word8
>>> x
255
Run Code Online (Sandbox Code Playgroud)
是否有任何类型会警告负面文字或有没有办法我可以创建自己的自定义类型,它会发出警告?
我正在问这个问题,希望能够完善Simon Marlow先前给出的一个问题的答案INLINABLE,链接在这里:
是否有任何理由不使用INLINABLE pragma作为函数?
我意识到这几乎是这个问题的重复,除了Simon Marlow没有回答对许多图书馆作者来说最重要的关键问题:从纯粹的性能角度来看,将INLINABLEpragma 添加到所有内容是否安全?
据我所知,唯一的缺点是:
编译时间较慢
更大的接口文件(即*.hi)
但我真正想知道的是,由于添加了INLINABLEpragma,代码是否会运行得更慢?换句话说,一个INLINABLEpragma是否会导致GHC选择一个不太理想的优化?
我问的原因是,包括我自己在内的许多库作者并不关心接口文件的大小,并且在添加INLINABLE编译指示时我们没有观察到编译的显着减慢,所以很容易在任何地方反复添加它们,因为那里这样做似乎没有代价.
相反,将它们ghc遗漏的成本是,当模块变得非常大时,开始选择性地从接口文件中省略一些函数以节省空间,这有时会导致更差的优化,并且很难预测这将发生在什么时候和它将省略哪些功能.
我个人从来没有目睹过由于INLINABLE注释而运行速度较慢的函数,但这可能完全归功于运气.如果有些情况INLINABLE会使事情变慢,我想知道为什么会这样做,以便我可以更好地推断何时添加编译指示而不是繁琐地对编译器编译指示的每个排列进行基准测试.
我正在关注Conor McBride的"Kleisli箭头的令人发指的财富"论文,我在这里发布了我的代码实现.简而言之,他定义了以下类型和类:
type a :-> b = forall i . a i -> b i
class IFunctor f where imap :: (a :-> b) -> (f a :-> f b)
class (IFunctor m) => IMonad m where
skip :: a :-> m a
bind :: (a :-> m b) -> (m a :-> m b)
data (a := i) j where
V :: a -> (a := i) i
Run Code Online (Sandbox Code Playgroud)
然后他定义了两种类型的绑定,后者(:=)用于限制初始索引:
-- Conor McBride's "demonic bind"
(?>=) …Run Code Online (Sandbox Code Playgroud) 基准测试表明,对于cereal我的数据结构(详见下文),反序列化所需的时间比从驱动器读取相同数据所需的时间长100倍:
benchmarking Read
mean: 465.7050 us, lb 460.9873 us, ub 471.0938 us, ci 0.950
std dev: 25.79706 us, lb 22.19820 us, ub 30.81870 us, ci 0.950
found 4 outliers among 100 samples (4.0%)
4 (4.0%) high mild
variance introduced by outliers: 53.460%
variance is severely inflated by outliers
benchmarking Read + Decode
collecting 100 samples, 1 iterations each, in estimated 6.356502 s
mean: 68.85135 ms, lb 67.65992 ms, ub 70.05832 ms, ci 0.950
std dev: 6.134430 ms, lb …Run Code Online (Sandbox Code Playgroud) Haskell允许您派生类型类实例,例如:
{-# LANGUAGE DeriveFunctor #-}
data Foo a = MakeFoo a a deriving (Functor)
Run Code Online (Sandbox Code Playgroud)
...但有时基准测试表明,如果您手动实现类型类实例并使用以下方法注释类型类方法,性能会提高INLINE:
data Foo a = MakeFoo a a
instance Functor Foo where
fmap f (MakeFoo x y) = MakeFoo (f x) (f y)
{-# INLINE fmap #-}
Run Code Online (Sandbox Code Playgroud)
有没有办法让两全其美?换句话说,有没有办法派生类型类实例,并使用INLINE?注释派生的类型类方法?
想象一下,我有一个比monad更通用的值:
m :: (Monad m) => m A -- 'A' is some concrete type
Run Code Online (Sandbox Code Playgroud)
现在让我们说我将这个值专门化为一个具体的monad变换器堆栈,有两种不同的方式:
m1 :: T M A
m1 = m
m2 :: T M A
m2 = lift m
Run Code Online (Sandbox Code Playgroud)
...在哪里M和T M是monad,并且T是monad变换器:
instance Monad M where ...
instance (Monad m) => Monad (T m) where ...
instance MonadTrans T where ...
Run Code Online (Sandbox Code Playgroud)
......这些实例遵守monad法律和monad变压器法则.
我们可以推断出:
m1 = m2
Run Code Online (Sandbox Code Playgroud)
...... m除了它的类型之外什么都不知道?
这只是一个冗长的方式,询问是否lift m是一个有效的替代m,假设两种类型检查.这个问题有点难以理解,因为它需要m在替换之前和之后将类型检查作为两个单独的monad.据我所知,这种替换进行类型检查的唯一方法m是在monad上是否通用.
我模糊的直觉是替换应该总是正确的,但我不确定我的直觉是否正确,或者如果它是正确的,如何证明它.
cabal dist阻止你使用,-O2因为它产生更长的编译时间,GHC手册说:
目前,
-O2不太可能产生比代码更好的代码-O.
我知道我总是可以对库进行基准测试,看看是否能-O2提供更好的性能,但我想知道是否有人可以解释有什么-O2不同,-O所以我可以直截了当地说他们认为不太可能产生更好的代码.
我正在尝试一个mtl允许我Pipe在外部monad 上提升构图的类式.为此,我必须定义该类型的哪两个变量是Pipe组合的域和codomain .
我尝试使用相关的类型系列方法,但无济于事:
{-# LANGUAGE TypeFamilies #-}
import Control.Monad.Trans.Free
import Control.Monad.Trans.State
import Control.Pipe hiding (Pipe)
data Pipe a b m r = Pipe { unPipe :: FreeT (PipeF a b) m r }
class MonadPipe m where
type C a b (m :: * -> *) :: * -> *
idT :: C a a m r
(<-<) :: C b c m r -> C a b m r -> C a …Run Code Online (Sandbox Code Playgroud) 我有一些做作的类型:
{-# LANGUAGE DeriveFunctor #-}
data T a = T a deriving (Functor)
Run Code Online (Sandbox Code Playgroud)
......那个类型是一些人为的类的实例:
class C t where
toInt :: t -> Int
instance C (T a) where
toInt _ = 0
Run Code Online (Sandbox Code Playgroud)
如何在一个函数约束中表达,它T a是一个所有类的实例a?
例如,请考虑以下功能:
f t = toInt $ fmap Left t
Run Code Online (Sandbox Code Playgroud)
直觉上,我希望,因为上面的功能工作toInt的作品T a为所有a,但我无法表达的类型.这不起作用:
f :: (Functor t, C (t a)) => t a -> Int
Run Code Online (Sandbox Code Playgroud)
...因为当我们应用fmap类型已成为Either a b.我无法解决这个问题:
f :: (Functor t, C (t …Run Code Online (Sandbox Code Playgroud)