Skip to content

GitLab

  • Menu
Projects Groups Snippets
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
  • Sign in / Register
  • GHC GHC
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
    • Locked Files
  • Issues 4,869
    • Issues 4,869
    • List
    • Boards
    • Service Desk
    • Milestones
    • Iterations
  • Merge requests 456
    • Merge requests 456
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
    • Test Cases
  • Deployments
    • Deployments
    • Releases
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Code review
    • Insights
    • Issue
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • Glasgow Haskell Compiler
  • GHCGHC
  • Issues
  • #18902
Closed
Open
Created Oct 29, 2020 by T@Proxymoron461

Significant difference in memory usage between Type Application and Type Signature

Summary

Using relatively large/complex types as arguments in type applications compiles significantly faster and using significantly less memory than when using type signatures. In testing, the example below requires around 41.5MB of memory when using type applications and compiles instantly, while it requires approximately 3.55GB of memory when using a type signature.

Steps to reproduce

Compile the code below, with one of the two equations of test given. With the type application, it will compile in a short amount of time with low memory usage, but compiling with the type signature will cause a massive rise in compilation time and memory usage.

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE RankNTypes #-}
import Data.Proxy
import GHC.TypeLits

data MyNat = Z | S MyNat

data Vector (n :: MyNat) a where 
    Empty :: Vector Z a 
    Cons :: a -> Vector n a -> Vector (S n) a
type family Replicate (n :: MyNat) (a :: k) :: Vector n k where 
    Replicate Z x = Empty 
    Replicate (S n) x = Cons x (Replicate n x)

type family ToMyNat (n :: Nat) :: MyNat where 
    ToMyNat 0 = Z 
    ToMyNat n = S (ToMyNat (n-1))

type Simple = Replicate (ToMyNat 0) (Replicate (ToMyNat 0) Black)
type Large = Replicate (ToMyNat 200) (Replicate (ToMyNat 200) Black)

type Spec t = forall m . (t -> m) -> m
data Colour = White | Black
data Dec :: Vector n k -> Colour -> * where 
    Dec :: Dec v a

test :: Spec (Proxy (Dec Large Black))
-- test cont = cont (Proxy @(Dec Large Black))
test cont = cont (Proxy :: Proxy (Dec Large Black))

Using :kind! in GHCi to evaluate Large to a normal form completes relatively quickly.

Expected behavior

Using a type signature vs using a type application should have similar compilation times and memory usage.

Environment

  • GHC version used: 8.8.4, 8.6.5

Optional:

  • Operating System: Linux (POP!_OS), MacOS, Windows
  • System Architecture: x86_64
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information
Assignee
Assign to
Time tracking