If I have nix installed, I can run pretty much any program, without having it "installed".
For instance a javascript program require node
//in file helloworld.js
const http = require('http'); // Loads the http module
http.createServer((request, response) => {
response.writeHead(200, {
'Content-Type': 'text/plain'
});
response.write('Hello, World!\n');
response.end();
}).listen(1337);
and I can directly run it with
$(nix-build -E "with import <nixpkgs> { };nodejs")/bin/node helloworld.js
For simple haskell, I can likewise both summon a haskell environment, and have it run directly with a bash script :
#! /usr/bin/env nix-shell
#! nix-shell -i runghc -p "haskellPackages.ghcWithPackages(p: with p; [type-level-sets])"
#! nix-shell -I nixpkgs=channel:nixos-21.11
-- courtesy jyrimatti https://gist.github.com/jyrimatti/bd139e91ed257d37bc57c08ac505fc3f
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeApplications #-}
module Main where
import Data.Type.Set (Set(..), Proxy(..))
class Get a s where
get :: Set s -> a
instance {-# OVERLAPS #-} Get a (a ': s) where
get (Ext a _) = a
instance {-# OVERLAPPABLE #-} Get a s => Get a (b ': s) where
get (Ext _ xs) = get xs
main :: IO ()
main = do
let lst = Ext "hello" $ Ext 10 $ Empty
putStrLn $ show $ get #String lst
However, say my program is more complicated, like the webserver example, and I want to target a particular package set. now all my dependencies are picked from that vetted set of packages which are known to be compatible with each others.
With stack installed, this is easy :
#!/usr/bin/env stack
-- stack --resolver lts-18.21 script
-- this script makes use of the http-client library, which is in stackage
{-# LANGUAGE OverloadedStrings #-}
import qualified Data.ByteString.Lazy.Char8 as L8
import Network.HTTP.Simple
-- An equivalent pure haskell file can also be run as
-- stack runghc --package http-conduit -- http.hs
main :: IO ()
main = do
response <- httpLBS "http://httpbin.org/get"
putStrLn $
"The status code was: "
++ show (getResponseStatusCode response)
print $ getResponseHeader "Content-Type" response
L8.putStrLn $ getResponseBody response
Is there an equivalent for nix which would make it simple to (reliably !) launch some haskell program, along with its dependencies, without anything special installed apart from nix ?
I imagine something like :
#! /usr/bin/env nix-shell
#! nix-shell -i runghc -p "stackage.lts-18.21"
#! nix-shell -I nixpkgs=channel:nixos-21.11
-- this script makes use of the http-client library, which is in stackage
{-# LANGUAGE OverloadedStrings #-}
import qualified Data.ByteString.Lazy.Char8 as L8
import Network.HTTP.Simple
-- An equivalent pure haskell file can also be run as
-- stack runghc --package http-conduit -- http.hs
main :: IO ()
main = do
response <- httpLBS "http://httpbin.org/get"
putStrLn $
"The status code was: "
++ show (getResponseStatusCode response)
print $ getResponseHeader "Content-Type" response
L8.putStrLn $ getResponseBody response
Related
Hello i am trying to write a ~1GB file in a timely manner.Is there any recommended method.Up until now the process takes somewhere in the order of tens of minutes . Am i wrong in using Text should i use ByteString ? (I have also used String)
pt="d:\\data2.csv"
cnt=400000000
main::IO()
main=do
let payload=dat
writeWithHandle pt dat
dat::Text
dat=Data.Text.pack "0744442339"
writeWithHandle::FilePath->Text->IO()
writeWithHandle path tx=do
handle<-openFile path WriteMode
writeTimes cnt handle dat
writeTimes::Int->Handle->Text->IO()
writeTimes cnt handle payload= forM_ ([0..cnt]) (\x->Data.Text.IO.hPutStrLn handle payload)
I do not understand why it is taking so much in the order of tens of minutes.Initially i was using writeFile but i thought that would mean continously opening and closing the file for each row so i used appendFile to no avail.
I would recommend using a Builder for this, which is an efficient way to fill up buffers and can be written directly to a Handle.
#!/usr/bin/env stack
-- stack --resolver ghc-8.6.4 script
{-# LANGUAGE OverloadedStrings #-}
import Data.ByteString.Builder (Builder, hPutBuilder)
import Data.Foldable (fold)
import System.IO (IOMode (WriteMode), withBinaryFile)
pt :: FilePath
pt = "data2.csv"
cnt :: Int
cnt = 400000000
main :: IO ()
main = writeWithHandle pt dat
dat :: Builder
dat = "0744442339"
writeWithHandle :: FilePath -> Builder -> IO ()
writeWithHandle path tx =
withBinaryFile path WriteMode $ \h ->
hPutBuilder h $ makeBuilder cnt tx
makeBuilder :: Int -> Builder -> Builder
makeBuilder cnt payload = fold $ replicate cnt $ payload <> "\n"
You can keep payload as a Text value instead if you'd like, and convert to a Builder using encodeUtf8Builder.
So I have the following code from Preventing caching of computation in Criterion benchmark and my aim is to be able to step from main directly into the function defaultMain in Criterion.Main :
{-# OPTIONS -fno-full-laziness #-}
{-# OPTIONS_GHC -fno-cse #-}
{-# LANGUAGE BangPatterns #-}
module Main where
import Criterion.Main
import Data.List
num :: Int
num = 100000000
lst :: a -> [Int]
lst _ = [1,2..num]
myadd :: Int -> Int -> Int
myadd !x !y = let !result = x + y in
result
mysum = foldl' myadd 0
main :: IO ()
main = defaultMain [
bgroup "summation"
[bench "mysum" $ whnf (mysum . lst) ()]
]
and the cabal file is :
name: test
version: 0.1.0.0
build-type: Simple
cabal-version: >=1.10
executable test
main-is: Main.hs
build-depends: base >=4.8 && <4.9,
criterion==1.1.0.0
default-language: Haskell2010
ghc-options: "-O3"
(using ghc 7.10.1 and cabal 1.22.0.0).
If from within cabal repl I try to set a breakpoint in criterion I get the following error :
*Main> :break Criterion.Main.defaultMain
cannot set breakpoint on defaultMain: module Criterion.Main is not interpreted
Furthermore if I try to add the package I get the following error :
*Main> :add *Criterion
<no location info>: module ‘Criterion’ is a package module
Failed, modules loaded: Main.
If I do within the directory git clone https://github.com/bos/criterion
and then add the following two lines to my cabal file :
other-modules: Criterion
hs-source-dirs: .
./criterion
then upon doing cabal build I get the following errors :
criterion/Criterion/IO.hs:23:0:
error: missing binary operator before token "("
#if MIN_VERSION_binary(0, 6, 3)
so I suspect that I have to do a full on merge of the criterion cabal
file with my cabal file above, which feels a bit excessive.
Is there an easier way for me to go about setting a breakpoint
in Criterion, so that I can step (when debugging in cabal repl/ghci) directly from my source into criterion's source? Thanks
p.s. There is a related question at Debugging IO in a package module inside GHCi but unfortunately it did not help.
This is how I managed to achieve the desired goal of being able to step (within cabal repl) from my code into the criterion source :
First do :
mkdir /tmp/testCrit
cd /tmp/testCrit
Download criterion-1.1.0.0.tar.gz
Unzip into /tmp/testCrit, so we should have /tmp/testCrit/criterion-1.1.0.0. In this directory we have Criterion.hs etc.
Then jump into the folder containing the criterion source and do :
cd /tmp/testCrit/criterion-1.1.0.0
cabal sandbox init
cabal install -j
Note that this creates a directory : /tmp/testCrit/criterion-1.1.0.0/dist/dist-sandbox-782e42f0/build/autogen which we shall use later
Back in /tmp/testCrit create a Main.hs file containing the benchmark code above and also the cabal file above, but merge it with the criterion cabal file contained in /tmp/testCrit/criterion-1.1.0.0 in the following way. Note the main new additions are the lines :
cc-options: -fPIC
which allows one to run it in cabal repl, and the following
lines :
hs-source-dirs:
./
./criterion-1.1.0.0
./criterion-1.1.0.0/dist/dist-sandbox-782e42f0/build/autogen
The full cabal file should then look like :
name: test
version: 0.1.0.0
build-type: Simple
cabal-version: >=1.10
executable test
main-is: Main.hs
build-depends:
base >=4.8 && <4.9,
aeson >= 0.8,
ansi-wl-pprint >= 0.6.7.2,
base >= 4.5 && < 5,
binary >= 0.5.1.0,
bytestring >= 0.9 && < 1.0,
cassava >= 0.3.0.0,
containers,
deepseq >= 1.1.0.0,
directory,
filepath,
Glob >= 0.7.2,
hastache >= 0.6.0,
mtl >= 2,
mwc-random >= 0.8.0.3,
optparse-applicative >= 0.11,
parsec >= 3.1.0,
statistics >= 0.13.2.1,
text >= 0.11,
time,
transformers,
transformers-compat >= 0.4,
vector >= 0.7.1,
vector-algorithms >= 0.4
default-language: Haskell2010
ghc-options: "-O3"
c-sources:
./criterion-1.1.0.0/cbits/cycles.c
./criterion-1.1.0.0/cbits/time-posix.c
hs-source-dirs:
./
./criterion-1.1.0.0
./criterion-1.1.0.0/dist/dist-sandbox-782e42f0/build/autogen
cc-options: -fPIC
Then in the main directory do :
cd /tmp/testCrit/
cabal sandbox init
cabal install -j
Then we can spin up a cabal repl and step directly into
criterion from our Main.hs code :
*Main> :break Criterion.Main.defaultMain
Breakpoint 0 activated at criterion-1.1.0.0/Criterion/Main.hs:79:15-43
*Main> main
Stopped at criterion-1.1.0.0/Criterion/Main.hs:79:15-43
_result :: [Benchmark] -> IO () = _
[criterion-1.1.0.0/Criterion/Main.hs:79:15-43] *Main> :step
Stopped at criterion-1.1.0.0/Criterion/Main.hs:(131,1)-(147,39)
_result :: IO () = _
[criterion-1.1.0.0/Criterion/Main.hs:(131,1)-(147,39)] *Main> :step
Stopped at criterion-1.1.0.0/Criterion/Main.hs:(131,29)-(147,39)
_result :: IO () = _
bs :: [Benchmark] = [_]
defCfg :: Criterion.Types.Config = _
[criterion-1.1.0.0/Criterion/Main.hs:(131,29)-(147,39)] *Main> :step
Stopped at criterion-1.1.0.0/Criterion/Main.hs:132:10-37
_result :: IO Criterion.Main.Options.Mode = _
defCfg :: Criterion.Types.Config = _
I am trying out haskell's kafka library from git and got this error.
To debug this error, i like to print stacktrace at the error line.
In python world, it is just,
import traceback; print traceback.print_exc()
(or) in java, it is
e.printStackTrace()
So, how to do the same in haskell world?
You can get stack traces in Haskell but it is not as convenient as just e.printStackTrace(). Here is a minimal example:
import Control.Exception
import Debug.Trace
getStack :: String -> SomeException -> IO a
getStack msg e = traceStack (show e) $ error msg
main :: IO ()
main = do
(head []) `catch` (getStack "error on main at head")
Finally, compile it with ghc -prof -fprof-auto StackTrace.hs and it will produce
Prelude.head: empty list
Stack trace:
Main.getStack (StackTrace.hs:5:9-56)
Main.main (StackTrace.hs:(8,9)-(9,74))
GHC.List.CAF (<entire-module>)
StackTrace.exe: error on main at head
I am trying to do a recursive descent of a directory structure using Haskell. I would like to only retrieve the child directories and files as needed (lazily).
I wrote the following code, but when I run it, the trace shows that all directories are visited before the first file:
module Main where
import Control.Monad ( forM, forM_, liftM )
import Debug.Trace ( trace )
import System.Directory ( doesDirectoryExist, getDirectoryContents )
import System.Environment ( getArgs )
import System.FilePath ( (</>) )
-- From Real World Haskell, p. 214
getRecursiveContents :: FilePath -> IO [FilePath]
getRecursiveContents topPath = do
names <- getDirectoryContents topPath
let
properNames =
filter (`notElem` [".", ".."]) $
trace ("Processing " ++ topPath) names
paths <- forM properNames $ \name -> do
let path = topPath </> name
isDirectory <- doesDirectoryExist path
if isDirectory
then getRecursiveContents path
else return [path]
return (concat paths)
main :: IO ()
main = do
[path] <- getArgs
files <- getRecursiveContents path
forM_ files $ \file -> putStrLn $ "Found file " ++ file
How can I interleave the file processing with the descent? Is the problem that the files <- getRecursiveContents path action gets performed before the following forM_ in main?
This is exactly the kind of problem that iteratees/coroutines were designed to solve.
You can easily do this with pipes. The only change I made to your getRecursiveContents was to make it a Producer of FilePaths and to respond with the file name instead of returning it. This lets downstream handle the file name immediately instead of waiting for getRecursiveContents complete.
module Main where
import Control.Monad ( forM_, liftM )
import Control.Proxy
import System.Directory ( doesDirectoryExist, getDirectoryContents )
import System.Environment ( getArgs )
import System.FilePath ( (</>) )
getRecursiveContents :: (Proxy p) => FilePath -> () -> Producer p FilePath IO ()
getRecursiveContents topPath () = runIdentityP $ do
names <- lift $ getDirectoryContents topPath
let properNames = filter (`notElem` [".", ".."]) names
forM_ properNames $ \name -> do
let path = topPath </> name
isDirectory <- lift $ doesDirectoryExist path
if isDirectory
then getRecursiveContents path ()
else respond path
main :: IO ()
main = do
[path] <- getArgs
runProxy $
getRecursiveContents path
>-> useD (\file -> putStrLn $ "Found file " ++ file)
This prints out each file immediately as it traverses the tree, and it does not require lazy IO. It's also very easy to change what you do with the file names, since all you have to do is switch out the useD stage with your actual file handling logic.
To learn more about pipes, I highly recommend you read Control.Proxy.Tutorial.
Using lazy IO / unsafe... is not a good way to go. Lazy IO causes many problems, including unclosed resources and executing impure actions within pure code. (See also The problem with lazy I/O on Haskell Wiki.)
A safe way is to use some iteratee/enumerator library. (Replacing problematic lazy IO was the motivation for developing these concepts.) Your getRecursiveContents would become a source of data (AKA enumerator). And the data will be consumed by some iterator. (See also Enumerator and iteratee on Haskell wiki.)
There is a tutorial on the enumerator library that just gives an example of traversing and filtering directory tree, implementing a simple find utility. It implements method
enumDir :: FilePath -> Enumerator FilePath IO b
which is basically just what you need. I believe you will find it interesting.
Also there is a nice article explaining iteratees in The Monad Reader, Issue 16: Iteratee: Teaching an Old Fold New Tricks by John W. Lato, the author of the iteratee library.
Today many people prefer newer libraries such as pipes. You may be interested in a comparison: What are the pros and cons of Enumerators vs. Conduits vs. Pipes?.
Thanks to the comment by Niklas B., here is the solution that I have:
module Main where
import Control.Monad ( forM, forM_, liftM )
import Debug.Trace ( trace )
import System.Directory ( doesDirectoryExist, getDirectoryContents )
import System.Environment ( getArgs )
import System.FilePath ( (</>) )
import System.IO.Unsafe ( unsafeInterleaveIO )
-- From Real World Haskell, p. 214
getRecursiveContents :: FilePath -> IO [FilePath]
getRecursiveContents topPath = do
names <- unsafeInterleaveIO $ getDirectoryContents topPath
let
properNames =
filter (`notElem` [".", ".."]) $
trace ("Processing " ++ topPath) names
paths <- forM properNames $ \name -> do
let path = topPath </> name
isDirectory <- doesDirectoryExist path
if isDirectory
then unsafeInterleaveIO $ getRecursiveContents path
else return [path]
return (concat paths)
main :: IO ()
main = do
[path] <- getArgs
files <- unsafeInterleaveIO $ getRecursiveContents path
forM_ files $ \file -> putStrLn $ "Found file " ++ file
Is there a better way?
I was recently looking at a very similar problem, where I'm trying to do a somewhat complicated search using the IO monad, stopping after I find the file I'm interested in. While the solutions using libraries like Enumerator, Conduit, etc. seem to be the best you could do at the time those answers were posted, I just learned IO became an instance of Alternative in GHC's base library about a year ago, which opens up some new possibilities. Here's the code I wrote to try it out:
import Control.Applicative (empty)
import Data.Foldable (asum)
import Data.List (isSuffixOf)
import System.Directory (doesDirectoryExist, listDirectory)
import System.FilePath ((</>))
searchFiles :: (FilePath -> IO a) -> FilePath -> IO a
searchFiles f fp = do
isDir <- doesDirectoryExist fp
if isDir
then do
entries <- listDirectory fp
asum $ map (searchFiles f . (fp </>)) entries
else f fp
matchFile :: String -> FilePath -> IO ()
matchFile name fp
| name `isSuffixOf` fp = putStrLn $ "Found " ++ fp
| otherwise = empty
The searchFiles function does a depth-first search of a directory tree, stopping when it finds what you're looking for, as determined by the function passed as the first argument. The matchFile function is just there to show how to construct a suitable function to use as the first argument for searchFiles; in real life you'd probably do something more complicated.
The interesting thing here is that now you can use empty to make an IO computation "give up" without returning a result, and you can chain computations together with asum (which is just foldr (<|>) empty) to keep trying computations until one of them succeeds.
I find it a little unnerving that the type signature of an IO action no longer reflects the fact that it may deliberately not produce a result, but it sure simplifies the code. I was previously trying to use types like IO (Maybe a), but doing so made it very hard to compose actions.
IMHO there's no longer much reason to use a type like IO (Maybe a), but if you need to interface with code that uses a type like that, it's easy to convert between the two types. To convert IO a to IO (Maybe a), you can just use Control.Applicative.optional, and going the other way, you can use something like this:
maybeEmpty :: IO (Maybe a) -> IO a
maybeEmpty m = m >>= maybe empty pure
I've tried this:
main = do
hSetBuffering stdin NoBuffering
c <- getChar
but it waits until the enter is pressed, which is not what I want. I want to read the character immediately after user presses it.
I am using ghc v6.12.1 on Windows 7.
EDIT: workaround for me was moving from GHC to WinHugs, which supports this correctly.
Yes, it's a bug. Here's a workaround to save folks clicking and scrolling:
{-# LANGUAGE ForeignFunctionInterface #-}
import Data.Char
import Foreign.C.Types
getHiddenChar = fmap (chr.fromEnum) c_getch
foreign import ccall unsafe "conio.h getch"
c_getch :: IO CInt
So you can replace calls to getChar with calls to getHiddenChar.
Note this is a workaround just for ghc/ghci on Windows. For example, winhugs doesn't have the bug and this code doesn't work in winhugs.
Might be a bug:
http://hackage.haskell.org/trac/ghc/ticket/2189
The following program repeats inputted characters until the escape key is pressed.
import IO
import Monad
import Char
main :: IO ()
main = do hSetBuffering stdin NoBuffering
inputLoop
inputLoop :: IO ()
inputLoop = do i <- getContents
mapM_ putChar $ takeWhile ((/= 27) . ord) i
Because of the hSetBuffering stdin NoBuffering line it should not be necessary to press the enter key between keystrokes. This program works correctly in WinHugs (sep 2006 version). However, GHC 6.8.2 does not repeat the characters until the enter key is pressed. The problem was reproduced with all GHC executables (ghci, ghc, runghc, runhaskell), using both cmd.exe and command.com on Windows XP Professional...
Hmm.. Actually I can't see this feature to be a bug. When you read stdin that means that you want to work with a "file" and when you turn of buffering you are saying that there is no need for read buffer. But that doesn't mean that application which is emulating that "file" should not use write buffer. For linux if your terminal is in "icanon" mode it doesn't send any input until some special event will occur (like Enter pressed or Ctrl+D). Probably console in Windows have some similar modes.
The Haskeline package worked for me.
If you need it for individual characters, then just change the sample slightly.
getInputLine becomes getInputChar
"quit" becomes 'q'
++ input becomes ++ [input]
main = runInputT defaultSettings loop
where
loop :: InputT IO ()
loop = do
minput <- getInputChar "% "
case minput of
Nothing -> return ()
Just 'q' -> return ()
Just input -> do outputStrLn $ "Input was: " ++ [input]
loop
From comment of #Richard Cook:
Use hidden-char: Provides cross-platform getHiddenChar function.
I used the haskeline package, suggested in other answers, to put together this simple alternative to getChar. It requests input again in the case that getInputChar returns Nothing. This worked for me to get past the issue; modify as needed.
import System.Console.Haskeline
( runInputT
, defaultSettings
, getInputChar
)
betterInputChar :: IO Char
betterInputChar = do
mc <- runInputT defaultSettings (getInputChar "")
case mc of
Nothing -> betterInputChar
(Just c) -> return c