Haskell Netwire - Type errors

309 views Asked by At

I have just started using netwire and I'm having trouble with the very basics.

The following code works fine for me:

main :: IO ()
main = testWire clockSession_ (for 3 . yeah)

yeah :: Monad m => Wire s () m a String
yeah = pure "yes"

But this does not:

main :: IO ()
main = testWire clockSession_ forYeah

forYeah :: (Show b, Show e) => Wire s e Identity a b
forYeah = for 3 . yeah

fails with error:

Could not deduce (b ~ [Char])
from the context (Show b, Show e)
bound by the type signature for
forYeah :: (Show b, Show e) => Wire s e Identity a b
  at /home/fiendfan1/workspace/Haskell/Haskell-OpenGL/src/Main.hs:12:12-54
  `b' is a rigid type variable bound by
      the type signature for
        forYeah :: (Show b, Show e) => Wire s e Identity a b
      at /home/fiendfan1/workspace/Haskell/Haskell-OpenGL/src/Main.hs:12:12
Expected type: Wire s e Identity a b
  Actual type: Wire s () Identity a String
In the second argument of `(.)', namely `yeah'
In the expression: for 3 . yeah
In an equation for `forYeah': forYeah = for 3 . yeah

So I changed it to:

forYeah :: Show e => Wire s e Identity a String

which gives me the error:

Could not deduce (e ~ ())
from the context (Show e)
  bound by the type signature for
             forYeah :: Show e => Wire s e Identity a String
  at /home/fiendfan1/workspace/Haskell/Haskell-OpenGL/src/Main.hs:12:12-49
  `e' is a rigid type variable bound by
      the type signature for
        forYeah :: Show e => Wire s e Identity a String
      at /home/fiendfan1/workspace/Haskell/Haskell-OpenGL/src/Main.hs:12:12
Expected type: Wire s e Identity a String
  Actual type: Wire s () Identity a String
In the second argument of `(.)', namely `yeah'
In the expression: for 3 . yeah
In an equation for `forYeah': forYeah = for 3 . yeah

Changing it to:

forYeah :: Wire s () Identity a String

Gives the following error:

No instance for (HasTime Integer s) arising from a use of `for'
Possible fix: add an instance declaration for (HasTime Integer s)
In the first argument of `(.)', namely `for 3'
In the expression: for 3 . yeah
In an equation for `forYeah': forYeah = for 3 . yeah

Can someone explain why this happens and how I can fix my second code example?

3

There are 3 answers

0
Cirdec On BEST ANSWER

Edit: Here's a complete, compiling, running solution to this problem:

module Main (
    main
) where

import Prelude hiding ((.), id)
import qualified Prelude as Prelude
import Control.Wire
import Control.Wire.Interval

main :: IO ()
main = testWire clockSession_ (withoutErrors forYeah)

yeah :: Monad m => Wire s e m a String
yeah = pure "yes"

forYeah :: (Num t, HasTime t s, Monoid e, Monad m) => Wire s e m a String
forYeah = for 3 . yeah

-- This just is an easy way to specify to use () as the type for errors in testWire
withoutErrors :: Wire s () m a b -> Wire s () m a b 
withoutErrors = Prelude.id

Here's the original answer, that discussed why we should change the type of yeah, and then the necessary changes to the type of forYeah:

Change the type of yeah to Monad m => Wire s e m a String. Monad m => (Wire s e m a) has an Applicative instance , so pure should exist without specifying that the second type argument to Wire in yeah's type is ().

Note: I don't use netwire and I haven't tried compiling this. I've only looked at the types in the documentation.

Edit: You probably also need to change the type of forYeah.

Wire also has a Category instance:

Monad m => Category (Wire s e m)

Category's . operator has the following type:

(.) :: cat b c -> cat a b -> cat a c

So for Wires it is:

(.) :: Monad m => Wire s e m b c -> Wire s e m a b -> Wire s e m a c

for has the following type:

for :: (HasTime t s, Monoid e) => t -> Wire s e m a a

So for 3 would have a type like (HasTime Int s, Monoid e) => Wire s e m a a. Combined with yeah's type of Monad m => Wire s e m a String, for 3 . yeah would have a type like

(HasTime Int s, Monoid e, Monad m) => Wire s e m a String

So we could probably change the type of forYeah to:

forYeah :: (HasTime Int s, Monoid e, Monad m) => Wire s e m a String

Edit: Even better type for forYeah

Since an integer numeral (without a decimal point) is actually equivalent to an application of fromInteger to the value of the numeral as an Integer, and fromInteger :: (Num a) => Integer -> a, the literal 3 actually has type Num t => t. The best type we can choose is therefore probably:

forYeah :: (Num t, HasTime t s, Monoid e, Monad m) => Wire s e m a String
0
bheklilr On

I just asked GHCi what the type was:

> :m Control.Wire
> :t for (3 :: Int) . pure "yes"
for 3 . pure "yes" :: (Monad m, HasTime Int s, Monoid e) => Wire s e m a [Char]
> :{
| let forYeah :: HasTime Int s => Wire s () Identity a String
|     forYeah = for 3 . pure "yes"
| :}
> :t forYeah
forYeah :: HasTime Int s => Wire s () Identity a String

So that works. However, when asking the type of testWire clockSession_ forYeah, I get an error saying that it can't match NominalDiffTime with Int, but since NominalDiffTime is also an instance of Num, it's pretty easy to just change the signature:

> :{
| let forYeah :: HasTime NominalDiffTime s => Wire s () Identity a String
|     forYeah = for 3 . pure "yes"
| :}
> :t testWire clockSession_ forYeah
testWire clockSession_ forYeah :: (Applicative m, MonadIO m) => m c

So that seems like it'd work.

Also, it worked when I defined yeah separately as

yeah :: Monad m => Wire s () m a String
yeah = pure "yes"

forYeah :: HasTime t s => Wire s () Identity a String
forYeah = for 3 . yeah

The problem seemed to be in the HasTime constraint. Since you had left it out, the compiler defaulted the literal 3 to the type Integer, but there is not an instance for HasTime Integer s for any s.

0
jamshidh On

It works for me when I change the type of forYeah to

forYeah::Wire (Timed NominalDiffTime ()) () Identity a String

It also works if you leave out the type of forYeah.