Earn extra honor and gain new allies!
Honor is earned for each new codewarrior who joins.
Learn more

The given code barely passes at the limit of 23, even with -O2 enabled on Preloaded. GHC actually does lots of GC during compilation, so I guess we can apply this article to reduce GC times. Unfortunately, +RTS option is not available in OPTIONS_GHC so I need kazk's help here.

{-# LANGUAGE GADTs         #-}
{-# LANGUAGE TypeFamilies  #-}
{-# LANGUAGE TypeOperators #-}

{-# OPTIONS_GHC -Wall -O2 #-}

module Kata.AdditionCommutes
  ( plusCommutes ) where

import Kata.AdditionCommutes.Definitions
  ( Z, S
  , Natural(..), Equal(..)
  , (:+:))

-- | x == x
refl :: Natural n -> Equal n n
refl NumZ     = EqlZ
refl (NumS n) = EqlS (refl n)

-- | a == b -> b == a
sym :: Equal a b -> Equal b a
sym EqlZ     = EqlZ
sym (EqlS p) = EqlS (sym p)

-- | a == b && b == c -> a == c
(<&>) :: Equal a b -> Equal b c -> Equal a c
(<&>) EqlZ EqlZ         = EqlZ
(<&>) (EqlS a) (EqlS b) = EqlS (a <&> b)

-- | s(a) + b == a + s(b)
shove :: Natural a -> Natural b -> Equal (S a :+: b) (a :+: S b)
shove NumZ m     = EqlS (refl m)
shove (NumS n) m = EqlS (shove n m)

-- | a + b == b + a
plusCommutes :: Natural a -> Natural b -> Equal (a :+: b) (b :+: a)
plusCommutes NumZ  NumZ = EqlZ
plusCommutes a (NumS b) = sym (shove a b) <&> EqlS (plusCommutes a b)
plusCommutes (NumS a) b = EqlS (plusCommutes a b) <&> shove b a

test.js is a simple concatenation of preloaded, code and test cases. Other three files are components of cw-2 module, and they have a dependency on chai.

Also, you can find all installed packages at ls node_modules. Everything except cw-2 is publicly available.

Code
Diff
  • const fs = require('fs')
    const cp = require('child_process')
    console.log(cp.execSync('pwd').toString())
    console.log(cp.execSync('ls').toString())
    console.log(cp.execSync('ls node_modules').toString())
    console.log(cp.execSync('ls node_modules/cw-2').toString())
    //console.log(this)
    const file1 = fs.readFileSync('/home/codewarrior/node/test.js')
    console.log(file1.toString())
    const file2 = fs.readFileSync('/home/codewarrior/node/node_modules/cw-2/index.js')
    console.log(file2.toString())
    const file3 = fs.readFileSync('/home/codewarrior/node/node_modules/cw-2/assertions.js')
    console.log(file3.toString())
    const file4 = fs.readFileSync('/home/codewarrior/node/node_modules/cw-2/utils.js')
    console.log(file4.toString())
  • 11
    const fs = require('fs')
    
    2+
    const cp = require('child_process')
    
    3+
    console.log(cp.execSync('pwd').toString())
    
    4+
    console.log(cp.execSync('ls').toString())
    
    5+
    console.log(cp.execSync('ls node_modules').toString())
    
    6+
    console.log(cp.execSync('ls node_modules/cw-2').toString())
    
    22
    //console.log(this)
    
    3
    const file1 = fs.readFileSync('/home/codewarrior/index.js')
    
    8+
    const file1 = fs.readFileSync('/home/codewarrior/node/test.js')
    
    44
    console.log(file1.toString())
    
    5
    const file2 = fs.readFileSync('/runner/frameworks/javascript/cw-2.js')
    
    10+
    const file2 = fs.readFileSync('/home/codewarrior/node/node_modules/cw-2/index.js')
    
    66
    console.log(file2.toString())
    
    7
    const file3 = fs.readFileSync('/runner/frameworks/javascript/chai-display.js')
    
    12+
    const file3 = fs.readFileSync('/home/codewarrior/node/node_modules/cw-2/assertions.js')
    
    88
    console.log(file3.toString())
    
    9
    const file4 = fs.readFileSync('/runner/frameworks/javascript/display.js')
    
    14+
    const file4 = fs.readFileSync('/home/codewarrior/node/node_modules/cw-2/utils.js')
    
    1010
    console.log(file4.toString())
    

index.js is a combination of preloaded, code and test cases with a bit of error handling. Other three files are required modules to run the tests.

const fs = require('fs')
//console.log(this)
const file1 = fs.readFileSync('/home/codewarrior/index.js')
console.log(file1.toString())
const file2 = fs.readFileSync('/runner/frameworks/javascript/cw-2.js')
console.log(file2.toString())
const file3 = fs.readFileSync('/runner/frameworks/javascript/chai-display.js')
console.log(file3.toString())
const file4 = fs.readFileSync('/runner/frameworks/javascript/display.js')
console.log(file4.toString())

Just a demo that passing -Ox flags does work (GHC 8 only).

{-# OPTIONS_GHC -O2 -optc-O3 #-}

module Example where

factorial n = product [1..n]
Testing
Frameworks

A slightly hacky way to reproduce the timing information after the runner got the outermost "Test" group removed.

module Example where

add = (+)
//
module Example where
Testing
Frameworks

The Preloaded section includes all Codewars-specific testing utilities to be added to Haskell 8 runner.

  • solutionShouldHide, solutionShouldHideAll replaces the legacy hidden functionality.
  • shouldBeApprox, shouldBeApproxPrec can be used for floating-point assertions.
    • shouldBeApprox has default absolute/relative margin of 1e-6.
Testing
Frameworks

Currently, the hiding test that tests for hidden modules is only available in Haskell 7. Unfortunately, the original source is not compatible with Haskell 8 runner, so we have to write it from scratch.

Here is a small attempt to analyze the import statements from the source code.

module Example where

import Prelude hiding (Bool(..), head, (/))
import Data.Maybe
import qualified Data.Map as Map
import Data.Map (Map(..), fromList)
import Data.Set (Set)
import Data.Monoid (Dual(getDual))

List of packages tested

  • megaparsec
  • hspec-megaparsec

If you can build a working attoparsec example, please post a kumite on it.

module Example where

import Text.Megaparsec
import Text.Megaparsec.Char

import Data.Void

type Parser = Parsec Void String

singleX :: Parser Char
singleX = char 'x'

List of packages recently added

  • parsec, attoparsec, megaparsec
  • hspec-attoparsec, hspec-megaparsec
  • regex-pcre, regex-tdfa, regex-posix

List of packages tested here

  • parsec
  • regex-*
module Example where

import qualified Text.Regex.Posix as Posix
import qualified Text.Regex.PCRE as PCRE
import qualified Text.Regex.TDFA as TDFA

import Text.Parsec
import Text.Parsec.Char
import Text.Parsec.String

-- The most basic functionalities of Regex modules

posixMatches :: String -> String -> Bool
posixMatches = (Posix.=~)

pcreMatches :: String -> String -> Bool
pcreMatches = (PCRE.=~)

tdfaMatches :: String -> String -> Bool
tdfaMatches = (TDFA.=~)

pcreVersion :: Maybe String
pcreVersion = PCRE.getVersion

-- The most basic functionalities of Parsec

number :: Parser Integer
number = (\a b -> read a) <$> many1 digit <*> eof

parseInt :: String -> Either ParseError Integer
parseInt = parse number ""