Skip to content
This repository has been archived by the owner on Oct 14, 2020. It is now read-only.

Implement Test.CodeWars.BlackList for Haskell 8 #691

Closed
Bubbler-4 opened this issue Feb 7, 2019 · 16 comments
Closed

Implement Test.CodeWars.BlackList for Haskell 8 #691

Bubbler-4 opened this issue Feb 7, 2019 · 16 comments

Comments

@Bubbler-4
Copy link
Contributor

Name: Test.CodeWars.BlackList
Language Name: Haskell 8
Website: Within codewars-runner-cli repo

Why?

For library re-implementation challenges, e.g. transpose or fold or whatever, the hidden feature is necessary to stop people import that exact thing. Unfortunately, its access is limited to legacy Haskell (v7), so any kata that has a hidden test is stuck to v7 and therefore out of future support. (Not that writing a new kata that requires hidden is a good idea in the first place...)

Is it possible?

Looking at its imports, simply having that file alongside the solution/test.hs files should enable import Test.CodeWars.BlackList, unless there's some insanity in Language.Haskell.Exts.*.

@kazk
Copy link
Member

kazk commented Feb 7, 2019

Language.Haskell.Exts.Annotated doesn't seem to exist anymore.

https://github.com/Codewars/codewars-runner-cli/blob/a07114084838a002c53d512f6502996ba81d9ed7/frameworks/haskell/Test/CodeWars/BlackList.hs#L3

I think we just need to use Language.Haskell.Exts.Parser instead.


I'll see if I can make it work, but if not, I guess I can add haskell-src-exts and let the community come up with something usable based on that, then extract that into a new module that can be included.

@Bubbler-4
Copy link
Contributor Author

That's a bad news (that there is some insanity). Can you add haskell-src-exts first? That will allow others to do interesting source code analysis other than just hidden (I have no idea right now though). Also, working it out within CW (say, kumite) is easier (IMO) to develop something compatible with CW.

@kazk
Copy link
Member

kazk commented Feb 7, 2019

Yeah, I started reading the documentation and it seemed to have changed a lot. I can't find the replacement for import Language.Haskell.Exts.Annotated.Simplify (sModule) for example.

I'll add haskell-src-exts and make this a community project.

Solution can be read from /workspace/solution.txt instead of using the environment variable.

I'll let you know when it's deployed.

@DonaldKellett

This comment has been minimized.

@kazk

This comment has been minimized.

@kazk kazk changed the title Expose Test.CodeWars.BlackList to Haskell 8 Implement Test.CodeWars.BlackList for Haskell 8 Feb 7, 2019
@kazk
Copy link
Member

kazk commented Feb 7, 2019

Added haskell-src-exts to Haskell 8

@Bubbler-4
Copy link
Contributor Author

Bubbler-4 commented Feb 7, 2019

Tried a few things, and it seems to be straightforward.

Given 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))

the import list from the result of parseFile "solution.txt" looks like (formatting by me, every () part is where source annotations would go):

[
  ImportDecl {
    importAnn = (), importModule = ModuleName () "Prelude",
    importQualified = False, importSrc = False, importSafe = False,
    importPkg = Nothing, importAs = Nothing,
    importSpecs = Just (
      ImportSpecList () True [
        IThingAll () (Ident () "Bool"),
        IVar () (Ident () "head"),
        IVar () (Symbol () "/")
      ]
    )
  },
  ImportDecl {
    importAnn = (), importModule = ModuleName () "Data.Maybe",
    importQualified = False, importSrc = False, importSafe = False,
    importPkg = Nothing, importAs = Nothing, importSpecs = Nothing
  },
  ImportDecl {
    importAnn = (), importModule = ModuleName () "Data.Map",
    importQualified = True, importSrc = False, importSafe = False,
    importPkg = Nothing, importAs = Just (ModuleName () "Map"), importSpecs = Nothing
  },
  ImportDecl {
    importAnn = (), importModule = ModuleName () "Data.Map",
    importQualified = False, importSrc = False, importSafe = False,
    importPkg = Nothing, importAs = Nothing,
    importSpecs = Just (
      ImportSpecList () False [
        IThingAll () (Ident () "Map"),
        IVar () (Ident () "fromList")
      ]
    )
  },
  ImportDecl {
    importAnn = (), importModule = ModuleName () "Data.Set",
    importQualified = False, importSrc = False, importSafe = False,
    importPkg = Nothing, importAs = Nothing,
    importSpecs = Just (
      ImportSpecList () False [
        IAbs () (NoNamespace ()) (Ident () "Set")
      ]
    )
  },
  ImportDecl {
    importAnn = (), importModule = ModuleName () "Data.Monoid",
    importQualified = False, importSrc = False, importSafe = False,
    importPkg = Nothing, importAs = Nothing,
    importSpecs = Just (
      ImportSpecList () False [
        IThingWith () (Ident () "Dual") [VarName () (Ident () "getDual")]
      ]
    )
  }
]

Related kumite.

The relevant parts for hidden seem to be importModule and importSpecs:

  • If importSpecs == Nothing, the importModule is imported as a whole.
  • If importSpecs matches Just (ImportSpecList _ False xs), the identifiers in xs are imported.
  • If importSpecs matches Just (ImportSpecList _ True xs), the identifiers in xs are hidden using hiding.

@Bubbler-4
Copy link
Contributor Author

Ok, finished writing hidden close enough to be usable, except that it doesn't accept single item yet.

@kazk
Copy link
Member

kazk commented Feb 7, 2019

@Bubbler-4 Looks great!

I don't think we need to be 100% compatible (unless we really need to keep GHC 7.10 compatibility for some reason) so we can have separate functions if that makes sense.

Maybe we can create Test.Hspec.Codewars to provide various utility functions for testing on Codewars like Test.Hspec.Megaparsec.

We can also name the function to match other assertions. Something like shouldNotUseModule, shouldHaveHiddenImport, etc?

@Bubbler-4
Copy link
Contributor Author

That module name is a good idea.

I think should* implies that the function is designed for infix usage, so I guess we can expose a black-box object that represents solution's imports, and have a use case like

solutionImports `shouldHide` Module "Data.List"
solutionImports `shouldHide` FromModule "Data.List" "tail"

or, probably better:

solutionShouldHide $ Module "Data.List"
solutionShouldHide $ FromModule "Data.List" "tail"
solutionShouldHideAll [Module "Data.List", Module "Data.Set", Module "Data.Map"]

Just for reminder, there's one more must-have for Test.Hspec.Codewars - shouldApproxEqual.

@kazk
Copy link
Member

kazk commented Feb 7, 2019

Yeah, I like solutionShouldHide and solutionShouldHideAll 👍


For shouldApproxEqual, I added HUnit-approx because it was requested, but I haven't actually tried using it.

@Bubbler-4
Copy link
Contributor Author

Well, I already made a complete module including approx assertions (with descriptive failure messages), so you don't need HUnit-approx (which is IMO somewhat obscure in terms of epsilon).

@kazk
Copy link
Member

kazk commented Feb 7, 2019

@Bubbler-4 Looks great!

I'll make a repository under Codewars org. Maybe https://github.com/Codewars/hspec-codewars . So you can open a PR and we can maintain this.

@kazk
Copy link
Member

kazk commented Feb 7, 2019

@Bubbler-4 can you open a PR on Codewars/hspec-codewars so you get the credit?

Just adding a file Test/Hspec/Codewars.hs should be good for now.

@Bubbler-4
Copy link
Contributor Author

PR submitted.

Codewars is just perfect for slacking at work (just kidding :)

@kazk kazk self-assigned this Feb 10, 2019
@kazk kazk added the status/ready Ready to be deployed label Feb 10, 2019
@kazk
Copy link
Member

kazk commented Feb 12, 2019

Test.Hspec.Codewars is now available to every kata. Thanks again for doing this.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants