0
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RebindableSyntax #-}

{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}

module Main where

import Control.Monad.Writer hiding ((>>))
import qualified Prelude as P
import Data.String (fromString)
import qualified Data.ByteString.Char8 as B
import Data.ByteString.Char8 (ByteString)
import Prelude hiding ((+),(-),(*),(/),(<=),(<),(==),(>),(>=),negate,exp,log,tanh)

infixl 1 |>
(|>) = flip ($)

newtype Method args = Method {method' :: (ByteString, args)}

class CudaOuter repr where
  include :: ByteString -> repr ()
  externCBlock :: repr () -> repr ()
  method :: ByteString -> repr (ins -> outs) -> repr (Method (ins -> outs))

data Statements =
  Statement ByteString
  | Indent
  | Dedent
  deriving Show

quote x = ["\"",x,"\""] |> B.concat

-- type StatementsParser = Writer [Statements] -- Ok
-- type StatementsParser = MonadWriter [Statements] m => m -- Error
newtype StatementsParser m x = StatementsParser {st :: m x}

instance MonadWriter [Statements] m => CudaOuter (StatementsParser m) where
  include x = [quote x |> Statement] |> tell |> StatementsParser

--- The outer level of the Cuda compiler language.
cuda_kernel_module kernel_name method_body_macro = do
  include "thrust/tuple.h"
  include "thrust/functional.h"
  include "cub/cub.cuh"
  externCBlock $ do
    method kernel_name method_body_macro
    return ()

main = print "Hello"

The code above gives me this error.

* The constraint `MonadWriter [Statements] m'
    is no smaller than the instance head
  (Use UndecidableInstances to permit this)
* In the instance declaration for `CudaOuter (StatementsParser m)'

I am not sure what the error means, but am decently sure that UndecidableInstances is not what I want here.

In the previous version of this, I used a writer instance, but I am not sure how to make it more generic with MonadWriter and MonadState constraints. I've tried putting typeclass constraints inside the StatementsParser newtype, but that did not work either.

Right now I am thinking that maybe the constraints need to be put in during class declaration, but that does not strike me as it either.

This is a bit confusing.

1) How can more complex typeclass constraints be put in during instance declaration?

2) Can typeclass constraints go into newtype declarations?

3) Instead of using a newtype as in the code fragment, can a type synonim be used instead so I do not have to do packing and unpacking?

Marko Grdinić
  • 3,798
  • 3
  • 18
  • 21
  • 2
    Did you read [this question](http://stackoverflow.com/questions/7198907/haskell-constraint-is-no-smaller-than-the-instance-head)? I believe you are breaking [condition b in section 7.6.3.2 of the standard](https://downloads.haskell.org/~ghc/7.0.1/docs/html/users_guide/type-class-extensions.html#instance-rules): i.e. you have the assertion `MonadWriter [Statements] m` which contains 1 constructor+1 variable = size 2, and your instance head contains again one constructor and one variable = size 2. Adding an other `newtype` layer should make things work, or just use `UndecidableInstances`. – Bakuriu Jan 28 '17 at 12:33
  • 1
    By the way, the name `UndecidableInstances` is frightining but it's actually a *harmless* extension: the only thing that might happen is that GHC enters an infinite loop during compilation, and once that happens you can just debug your code and find which declarations/instances cause the infinite loop and refactor your code to avoid it, but it doesn't do anything other than that, so if the program terminates compilation it works fine. – Bakuriu Jan 28 '17 at 12:37

0 Answers0