Top-level expression evaluation at compile time - haskell

Is there any way to ensure, that an expression like the following would be evaluated at compile time?
myList :: [Int]
myList = sort [3,2,0,1]

If what you're evaluating is an instance of Lift, you can evaluate it at compile time using TemplateHaskell:
{-# LANGUAGE TemplateHaskell #-}
module Sort where
import Data.List
import Language.Haskell.TH.Syntax
myList :: [Int]
myList = $(lift (sort [3,2,0,1] :: [Int]))
If you want, you can check what it has compiled to with -ddump-splices:
$ ghc -ddump-splices sort
[1 of 1] Compiling Sort ( sort.hs, sort.o )
sort.hs:9:12-41: Splicing expression
lift (sort [3, 2, 0, 1] :: [Int]) ======> [0, 1, 2, 3]

Related

Couldn't match type ‘[Char]’ with ‘Data.Text.Internal.Text’

I am trying to figure out, how to build JSON in Haskell with the following example:
module Main where
import GHC.Exts
import Data.Aeson
import qualified Data.Text.Lazy.IO as T
import qualified Data.Text.Lazy.Encoding as T
val :: Value
val = Object $ fromList [
("numbers", Array $ fromList [Number 1, Number 2, Number 3]),
("boolean", Bool True) ]
main :: IO ()
main = T.putStrLn . T.decodeUtf8 . encode $ val
When I tried to compile, the compiler complains:
• Couldn't match type ‘[Char]’ with ‘Data.Text.Internal.Text’
Expected type: Item Object
Actual type: ([Char], Value)
• In the expression: ("boolean", Bool True)
In the first argument of ‘fromList’, namely
‘[("numbers", Array $ fromList [Number 1, Number 2, ....]),
("boolean", Bool True)]’
In the second argument of ‘($)’, namely
‘fromList
[("numbers", Array $ fromList [Number 1, Number 2, ....]),
("boolean", Bool True)]’
|
12 | ("boolean", Bool True) ]
| ^^^^^^^^^^^^^^^^^^^^^^
You need to put OverloadedStrings extension on top of the file:
#!/usr/bin/env stack
-- stack script --resolver lts-12.7
{-# LANGUAGE OverloadedStrings #-}
import Data.Aeson
import qualified Data.Text.Lazy.Encoding as T
import qualified Data.Text.Lazy.IO as T
import GHC.Exts
val :: Value
val =
Object $
fromList
[ ("numbers", Array $ fromList [Number 1, Number 2, Number 3])
, ("boolean", Bool True)
]
main :: IO ()
main = T.putStrLn . T.decodeUtf8 . encode $ val
And on executing them:
$ stack fuse.hs
{"boolean":true,"numbers":[1,2,3]}
To understand the reasons on why that makes it work, refer to this answer.
The error you get is about wrong string representation. Haskell has many of them, e.g. ByteString (strict or lazy), Text (strict or lazy), String (alias for [Char]). The last one is the default and also the one you should avoid most of the time.
Aeson library uses the Text as string representation. You can fix your code using T.pack before the string (to convert it to Text), like this:
val :: Value
val =
Object $
fromList
[ (T.pack "numbers", Array $ fromList [Number 1, Number 2, Number 3])
, (T.pack "boolean", Bool True)
]
Or you can just enable OverloadedStrings extension. When it's on then Haskell compiler will try to figure out which string representation it should use. Just put {-# LANGUAGE OverloadedStrings #-} at the top of your file and it should work.

Hspec unable to load interface for Spec file

I am trying to run hspec but getting error as "Failed to load interface for Spec file". I tried similar example from github, got same error. Please suggest where I am going wrong...(PS: I am able to run this with stack).
Example from github (https://github.com/FranklinChen/twenty-four-days2015-of-hackage)
I have following files:
-- src.HintExample.hs
module HintExample where
import SortWrapper (Sort)
import qualified Language.Haskell.Interpreter as I
import Language.Haskell.Interpreter (OptionVal((:=)))
-- | Dynamically load a 'Sort' implementation from a file.
-- src is needed to pick up our SortWrapper.
-- sort-plugins is a sample user plugins directory
loadSort :: I.MonadInterpreter m =>
String -- ^ module name
-> String -- ^ function name
-> m Sort
loadSort moduleName functionName = do
I.set [I.searchPath := ["src", "sort-plugins"]]
I.loadModules [moduleName]
I.setImports [moduleName, "SortWrapper"]
I.interpret (moduleName ++ "." ++ functionName) (I.as :: Sort)
And test file as
-- test.HintExampleSpec.hs
module HintExampleSpec where
import SortWrapper (Sort(Sort))
import HintExample (loadSort)
import qualified Language.Haskell.Interpreter as I
import Test.Hspec (Spec, hspec, describe, it, shouldBe)
import Test.Hspec.QuickCheck (prop)
-- | Required for auto-discovery.
spec :: Spec
spec =
describe "hint" $ do
it "dynamically loads a correct polymorphic sort function" $ do
Right (Sort ourSort) <-
I.runInterpreter (loadSort "OurSorter" "ourSort")
ourSort "ebcad" `shouldBe` "abcde"
ourSort [1 :: Int, 5, 4, 3, 7] `shouldBe` [1, 3, 4, 5, 7]
it "dynamically loads a wrong (only head) sort function" $ do
Right (Sort onlyHead) <-
I.runInterpreter (loadSort "OurSorter" "onlyHead")
onlyHead "ebcad" `shouldBe` "e"
onlyHead [True, False] `shouldBe` [True]
main :: IO ()
main = hspec spec
Spec file (Spec.hs) in test directory as:
{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
running as:
runhaskell test/Spec.hs

Having trouble generating arbitrary json with Haskell's Aeson package

I'm a Haskell newb, having only just finished reading LYAH. I am reading this Aeson tutorial, but I'm having trouble executing most of the code examples. For instance, I have the following in Scratch01.hs ...
{-# LANGUAGE OverloadedStrings #-}
module Scratch01 where
import Data.Aeson
import GHC.Exts
val :: Value
val = Object $ fromList [
("numbers", Array $ fromList [Number 1, Number 2, Number 3]),
("boolean", Bool True) ]
... and I'm trying to execute it like this
$ ghci --version
The Glorious Glasgow Haskell Compilation System, version 7.8.3
$ ghci -XOverloadedStrings
GHCi, version 7.8.3: http://www.haskell.org/ghc/ :? for help
Prelude> :load Scratch01.hs
[1 of 1] Compiling Scratch01 ( Scratch01.hs, interpreted )
Scratch01.hs:10:3:
Couldn't match expected type ‘Item Object’
with actual type ‘(t0, Value)’
The type variable ‘t0’ is ambiguous
In the expression:
("numbers", Array $ fromList [Number 1, Number 2, Number 3])
In the first argument of ‘fromList’, namely
‘[("numbers", Array $ fromList [Number 1, Number 2, ....]),
("boolean", Bool True)]’
In the second argument of ‘($)’, namely
‘fromList
[("numbers", Array $ fromList [Number 1, Number 2, ....]),
("boolean", Bool True)]’
Scratch01.hs:10:33:
Couldn't match expected type ‘Item Array’ with actual type ‘Value’
In the expression: Number 1
In the first argument of ‘fromList’, namely
‘[Number 1, Number 2, Number 3]’
Failed, modules loaded: none.
Prelude>
I've been tinkering with the types for a bit, but I'm stumped. Am I using the wrong version of GHC or something?
Edit
I did what artyom suggested. This works:
{-# LANGUAGE OverloadedStrings #-}
module Scratch01 where
import Data.Aeson
import qualified Data.HashMap.Lazy as HM
import qualified Data.Vector as V
val :: Value
val = Object $ HM.fromList [
("numbers", Array $ V.fromList [Number 1, Number 2, Number 3]),
("boolean", Bool True) ]

Template Haskell and Implicit Parameters

Is there a way to create functions with implicit parameters or let bindings with implicit parameters using template haskell?
I.e. is it possible to generate a signature like this using template haskell:
doSomething :: (?context :: Context) => m a
Or an invocation like this:
invoc = let ?context = newContext in doSomething
I could not find suitable algebraic data types nor any functions which would help me out on this topic in the API documentation for template haskell. I'm using GHC 7.4.2.
If there is no native support for this extension in template haskell, is there some other possibility to inject code during compilation (maybe something like a general “code injection function” within template haskell?).
EDIT: I tried the suggestion from the comments, this is what happens:
runQ [d| f :: (?c :: String) => Int ; f = 7 |]
<interactive>:10:17: parse error on input `c'
whereas this works:
runQ [d| f :: Int ; f = 7|]
[SigD f_0 (ConT GHC.Types.Int),ValD (VarP f_0) (NormalB (LitE (IntegerL 7))) []]
doesn't seem to be supported.
Here's one way that's pretty fragile, but sort of works. While you can't refer
to ?x in the Exp that template haskell uses, you can refer to a definition in
another module like:
reserved_prefix_x = ?x
Below is some code that generates variables like above in one run of ghc,
and in a second run of ghc the variables actually refer to implicit parameters.
{-# LANGUAGE TemplateHaskell, NoMonomorphismRestriction #-}
module GenMod (h) where
import Data.Generics
import Data.IORef
import Data.List
import Language.Haskell.Meta.Parse as P
import Language.Haskell.TH
import Language.Haskell.TH.Quote
import Language.Haskell.TH.Syntax
import qualified Data.Set as S
import qualified Language.Haskell.Exts.QQ as Q
import System.IO.Unsafe
h = Q.hs { quoteExp = \s -> do
r <- either fail (upVars . return) (P.parseExp s)
writeMod'
return r
}
pfx = "q_"
{-# NOINLINE vars #-}
vars :: IORef (S.Set String)
vars = unsafePerformIO (newIORef S.empty)
writeMod' = runIO $ writeFile "GEN.hs" . ppMod =<< readIORef vars
writeMod = -- might be needed to avoid multiple calls to writeFile?
-- in this example this is called for every use of `h'
QuasiQuoter { quoteDec = \ _ -> do
writeMod'
[d| _ = () |] }
ppMod xs = "{-# LANGUAGE NoMonomorphismRestriction, ImplicitParams #-}\n\
\module GEN where\n" ++
unlines (map (\x -> pfx ++ x ++ " = ?" ++ x) (S.toList xs))
upVars x = do
x' <- x
runIO $ modifyIORef vars (S.union (getMatchingVars x'))
runIO $ print =<< readIORef vars
return x'
getMatchingVars =
everything
S.union
(mkQ S.empty
(\ (OccName x) -> maybe S.empty S.singleton (stripPrefix pfx x)))
A Main.hs file that uses the quasiquoter GenMod.hs:
{-# LANGUAGE NoMonomorphismRestriction, ImplicitParams, QuasiQuotes, TemplateHaskell, CPP #-}
import GenMod
#ifndef stage1
import GEN
#endif
f_ = [h| q_hithere |]
You have to call ghc twice, like:
ghci -Dstage1 Main.hs
GHCi, version 7.6.1: http://www.haskell.org/ghc/ :? for help
[1 of 2] Compiling GenMod ( GenMod.hs, interpreted )
[2 of 2] Compiling Main ( Ex.hs, interpreted )
fromList ["hithere"]
Ex.hs:8:6: Not in scope: `q_hithere'
Failed, modules loaded: GenMod.
Though ghc fails, it still generates the GEN.hs which contains:
{-# LANGUAGE NoMonomorphismRestriction, ImplicitParams #-}
module GEN where
q_hithere = ?hithere
Which will be there when you load Main (leaving out the -D flag)
*Main> :t f_
f_ :: (?hithere::t) => t
This kind of trouble probably isn't worth it. Maybe other situations of calling out to other programs from TH are more motivating such as inline calls to other languages http://hpaste.org/50837 (gfortran example)
Since I used haskell-src-meta's default parser, the quasiquote gets to use variables "reserved_prefix_x" not "?x". It should be possible to accept the "?x" without too much difficulty.

Proper way to import things already defined in the Prelude in Haskell

I'm trying to define a Foldable instance in Haskell and I have some problem with import.
So first try :
module MyList
where
import Data.Foldable
data MyList a = MyList [a]
instance Foldable (MyList) where
foldr f b (MyList as) = foldr f b as
Result (normal but annoying)
Ambiguous occurrence `foldr'
So, I guess I have to hide it from the Prelude :
module MyList
where
import Prelude hiding (foldr)
import Data.Foldable
data MyList a = MyList [a]
instance Foldable (MyList) where
foldr f b (MyList as) = foldr f b as
This compile, I load into ghci and try some basic stuff :
*MyList> foldr (:) "" (MyList "hello")
"hello"
*MyList> foldl (flip (:)) "" (MyList "hello")
<interactive>:1:0:
Ambiguous occurrence `foldl'
It could refer to either `Prelude.foldl', imported from Prelude at MyList.hs:4:0-28
or `Data.Foldable.foldl', imported from Data.Foldable at MyList.hs:5:0-19
*MyList>
So foldr works, but foldl doesn't. My first question is
Do I have to hide manually every single method defined in Data.Foldable from the Prelude is their a nice way to do it ?.
To avoid this problem , I tried to do an qualified import :
module MyList
where
import qualified Data.Foldable as F
data MyList a = MyList [a]
instance F.Foldable (MyList) where
foldr f b (MyList as) = foldr f b as
Seems to compile in ghc but
*MyList> foldr (:) "" (MyList "hello")
<interactive>:1:14:
Couldn't match expected type `[Char]'
against inferred type `MyList Char'
In the third argument of `foldr', namely `(MyList "hello")'
In the expression: foldr (:) "" (MyList "hello")
In the definition of `it': it = foldr (:) "" (MyList "hello")
foldr is not found but suprisingly F.foldr works in ghci.
*MyList> F.foldr (:) "" (MyList "hello")
"hello"
But in ghci only, if I'm trying to import MyList in file, foldr, F.foldr, MyList.F.foldr and MyList.foldr doesn't work.
Why does it work in ghci but not in real ?
I guess I have to import Data.Foldable again (and again in every files using MyList)
Is there a better way to do it (like exporting Data.Foldable in MyList) ?
(I'm a newbie in Haskell and especially with modules)
After having a couple of responses, it seems there is no clean solution to this problem. However, I'm pretty sure I'm not the first doing that, so
What is the common practice to deal with that kind of problem?
Thanks for you help.
Why does it work in ghci but not in real?
Because in your GHCi session you were typing expressions in the context of the MyList module, so F.foldr was in scope, but if you import MyList into another module then only the names exported by MyList, and the other modules you imported, are in scope.
Your guess is correct - in every module using Data.Foldable.foldr, you have to
import qualified Data.Foldable as F
The names exported by a module are unqualified; the qualification or not of those names is decided when the module is imported.
There have been proposals over the years to allow exporting qualified names, but to date nothing has been implemented.
Regarding the implicit Prelude import, you could add the following language pragma, and then explicitly import things from Prelude, but it might get uglier than simply hiding things from the Prelude or using an qualified import of Data.Foldable.
{-# LANGUAGE NoImplicitPrelude #-}
import Prelude (someFunction)
Why it might get uglier? Because you might have to import data types and functions that are taken for granted, or even functions that aren't explicitly used in the code:
{-# LANGUAGE NoImplicitPrelude #-}
module Main (main) where
-- we import fromInteger although it's not explicitly used
import Prelude (Int, foldl, fromInteger, (+), putStrLn, (.), ($), IO, show)
sum :: [Int] -> Int
sum = foldl (+) 0
main :: IO ()
main = putStrLn . show $ sum [1,2,3]
I told you about this not because it's a good solution, but just to know that there's such a thing.
Here's a variant of Thomas Eding solution, with less typing. Basically, you can import (in Prelude') Prelude hiding some functions, and then reexport Prelude; this will export Prelude minus those functions. This technique is generally useful to write a frontend module re-exporting only some functions in a library.
You can then reexport also Data.Foldable.
Where I replaced some Prelude functions with equivalents (examples for Foldable and Category).
module Prelude2 (module Prelude, module Data.Foldable, module Control.Category) where
import Prelude hiding (id, (.), foldr)
import Data.Foldable (Foldable, foldr) -- You might want to import everything.
import Control.Category (Category((.), id))
-- Try out replacing with:
-- import Control.Category ()
-- to see that no (.) is available.
Usage:
module Foo where
import Prelude()
import Prelude2
To wit, notice the types of foldr and (.) in Foo, as shown by GHCi:
$ ghci Foo.hs
GHCi, version 7.6.3: http://www.haskell.org/ghc/ :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
[1 of 2] Compiling Prelude2 ( src-lib/Prelude2.hs, interpreted )
[2 of 2] Compiling Foo ( /Users/pgiarrusso/AeroFS/Repos/pts-bluevelvet/src-lib/Foo.hs, interpreted )
Ok, modules loaded: Foo, Prelude2.
*Foo> :t foldr
foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
*Foo> :t (.)
(.) :: Category cat => cat b c -> cat a b -> cat a c
*Foo>
If you try the suggestion of replacing
import Control.Category ()
GHCi will show you that (.) is not defined at all in Foo:
*Foo> :r
[1 of 2] Compiling Prelude2 ( src-lib/Prelude2.hs, interpreted )
[2 of 2] Compiling Foo ( /Users/pgiarrusso/AeroFS/Repos/pts-bluevelvet/src-lib/Foo.hs, interpreted ) [Prelude2 changed]
Ok, modules loaded: Foo, Prelude2.
*Foo> :t (.)
<interactive>:1:1: Not in scope: `.'
You could make a Prelude' module that exports only the stuff you want. Then you could begin your actual module as follows:
import Prelude ()
import Prelude'
import Data.Foldable
Granted you have to do the grunt work in Prelude', but at least it is reusable.
Clarification:
Prelude'.hs:
module Prelude' (
id
, Num (..)
, everthing you want exported for your 'customized' prelude module goes in this list
) where
I've re-read your question and some of your comments and I guess the closest you can get to what you want is something like this:
module MyList
(
module Data.Foldable,
MyList(..)
)
where
import Data.Foldable
import Prelude (($))
data MyList a = MyList [a]
instance Foldable (MyList) where
foldr f b (MyList as) = foldr f b as
Basically, MyList re-exports the Data.Foldable module, so that someone using your module won't have to import Data.Foldable again, but... she will have to hide some functions from the Prelude.
module Main (main) where
import Prelude hiding (foldr)
import MyList
mySum :: MyList Int -> Int
mySum = foldr (+) 0
main :: IO ()
main = putStrLn . show . mySum $ MyList [1,2,3]
IMHO, this is a good thing. You should not decide how and what someone imports in his own modules.

Resources