How can I get an modulo of a calculation in Haskell? - haskell

I am simply trying to get the Unixtime of the current day. For that I wanted to get the modulo of the current time divided by the timespan of one day. .
yourUnixTime = k / 86400
modunix = mod yourUnixTime 1
main = do
putStrLn "give me your time"
k <- readLn
putStrLn $ "time: " ++show (modunix yourUnixTime)
This is my current code. So why does my code not work?
It says "Variable not in scope: k" I also tried to put a "k" between the "yourUnixTime" and the equal sign, didnt work either (with even more errors I can't understand). So the answer I am hoping for is how I can fix it and/or what other solutions are there.

You are trying to use the variable k before it has been defined or initialized.
Here is the modified version of the code
main = do
putStrLn "Enter the current time:"
k <- readLn
let (unixTime, modUnix) = k `divMod` 86400
putStrLn $ "Unix time of the current day: " ++ show modUnix

Related

How to print output on a single line?

Today I was working on this code which outputs the average value of a series of "arrays", the data is inputted in this format:
3 #Number of arrays to get the average from
2 3 0 #First array
4 5 0 #Second array
1 4 5 0 #Third array
I worked on a code that outputs the data, but realized that it prints it like this:
2 #Average (Int) of the 1st array
4 #Average (Int) of the 2nd array
3 #Average (Int) of the 3rd array
(Take into account that the 0 at the end of every array is not used when calculated the average, it only exists for means of indicating end of array)
My question is, How can I properly change my code so that I can output the data like this? :
2 4 3
Here is the code I've been working in:
sumList :: [Int] -> Int sumList [] = 0 sumList (u:v) = u + sumList v
funavg :: Int -> IO () funavg numitint = if numitint==0 then return ()
else do
arrs <- getLine
let arrnum = (map read(words arrs) :: [Int])
let total = sumList arrnum
let avg = div total ((length arrnum)-1)
print avg
funavg (numitint - 1)
main :: Prelude.IO () main = do
numits <- getLine
let numitint = read numits :: Int
funavg numitint
I've searched many documents and websites, but can't come with an ideal answer.
Using recursion is mandatory.
Any help is highly appreciated :D
print is equivalent to putStrLn . show and is provided for convenience to print a single value of any Show type.
print does not have a standard library companion which omits the newline, but putStrLn does: it's called putStr. Instead of print avg, consider
putStr $ show avg

How to change an element in [String] in Haskell?

I'm working on a program that receives as input a board game as follows:
#####
#_ ##
# ##
# #
# .#
#####
1 4 (player initial position, marked with '_')
After receiving the input, the program transforms it to a [String].
This case, it would be:
["#####", "#_ ##", "# ##", "# #", "# .#", "#####", "1 4"]
How can I access position [1,4] and transform '_' to 'o'?
Function must return initial list with that transformation.
Very important note: '_' is never displayed on input, I only used it to make clear where position [1,4] is (therefore, on input we only see a blank space, ' ')
Seems like one of those tasks you might have to solve for online coding games. As others pointed out, lists are not really suited for dealing with coordinates like this. However, if you are not able to use better libraries (like in coding games) you will have to do some more work.
Here is the code from my ghci session (transforming to a proper program is left as an exercise for the reader...):
let input = ["#####", "#_ ##", "# ##", "# #", "# .#", "#####", "1 4"]
let reverseInput = reverse input
let position = head reverseInput
let board = tail reverseInput
let posX = read $ takeWhile (/=' ') position :: Int
let posY = read $ takeWhile (/=' ') $ reverse position :: Int
let (unchangedBoard, changedBoard) = splitAt posY board
let (unchangedRow, changedRow) = splitAt posX $ head changedBoard
let newRow = unchangedRow ++ "o" ++ tail changedRow
let newBoard = unchangedBoard ++ [newRow] ++ tail changedBoard
let finalOutput = reverse newBoard
mapM_ putStrLn finalOutput
Also note this code is very brittle as it uses partial functions all over the place (tail, head, read). You could try to use pattern matching instead to make the code more robust.

algorithm/code in R to find pattern from any position in a string

I want to find the pattern from any position in any given string such that the pattern repeats for a threshold number of times at least.
For example for the string "a0cc0vaaaabaaaabaaaabaa00bvw" the pattern should come out to be "aaaab". Another example: for the string "ff00f0f0f0f0f0f0f0f0000" the pattern should be "0f".
In both cases threshold has been taken as 3 i.e. the pattern should be repeated for at least 3 times.
If someone can suggest an optimized method in R for finding a solution to this problem, please do share with me. Currently I am achieving this by using 3 nested loops, and it's taking a lot of time.
Thanks!
Use regular expressions, which are made for this type of stuff. There may be more optimized ways of doing it, but in terms of easy to write code, it's hard to beat. The data:
vec <- c("a0cc0vaaaabaaaabaaaabaa00bvw","ff00f0f0f0f0f0f0f0f0000")
The function that does the matching:
find_rep_path <- function(vec, reps) {
regexp <- paste0(c("(.+)", rep("\\1", reps - 1L)), collapse="")
match <- regmatches(vec, regexpr(regexp, vec, perl=T))
substr(match, 1, nchar(match) / reps)
}
And some tests:
sapply(vec, find_rep_path, reps=3L)
# a0cc0vaaaabaaaabaaaabaa00bvw ff00f0f0f0f0f0f0f0f0000
# "aaaab" "0f0f"
sapply(vec, find_rep_path, reps=5L)
# $a0cc0vaaaabaaaabaaaabaa00bvw
# character(0)
#
# $ff00f0f0f0f0f0f0f0f0000
# [1] "0f"
Note that with threshold as 3, the actual longest pattern for the second string is 0f0f, not 0f (reverts to 0f at threshold 5). In order to do this, I use back references (\\1), and repeat these as many time as necessary to reach threshold. I need to then substr the result because annoyingly base R doesn't have an easy way to get just the captured sub expressions when using perl compatible regular expressions. There is probably a not too hard way to do this, but the substr approach works well in this example.
Also, as per the discussion in #G. Grothendieck's answer, here is the version with the cap on length of pattern, which is just adding the limit argument and the slight modification of the regexp.
find_rep_path <- function(vec, reps, limit) {
regexp <- paste0(c("(.{1,", limit,"})", rep("\\1", reps - 1L)), collapse="")
match <- regmatches(vec, regexpr(regexp, vec, perl=T))
substr(match, 1, nchar(match) / reps)
}
sapply(vec, find_rep_path, reps=3L, limit=3L)
# a0cc0vaaaabaaaabaaaabaa00bvw ff00f0f0f0f0f0f0f0f0000
# "a" "0f"
find.string finds substring of maximum length subject to (1) substring must be repeated consecutively at least th times and (2) substring length must be no longer than len.
reps <- function(s, n) paste(rep(s, n), collapse = "") # repeat s n times
find.string <- function(string, th = 3, len = floor(nchar(string)/th)) {
for(k in len:1) {
pat <- paste0("(.{", k, "})", reps("\\1", th-1))
r <- regexpr(pat, string, perl = TRUE)
if (attr(r, "capture.length") > 0) break
}
if (r > 0) substring(string, r, r + attr(r, "capture.length")-1) else ""
}
and here are some tests. The last test processes the entire text of James Joyce's Ulysses in 1.4 seconds on my laptop:
> find.string("a0cc0vaaaabaaaabaaaabaa00bvw")
[1] "aaaab"
> find.string("ff00f0f0f0f0f0f0f0f0000")
[1] "0f0f"
>
> joyce <- readLines("http://www.gutenberg.org/files/4300/4300-8.txt")
> joycec <- paste(joyce, collapse = " ")
> system.time(result <- find.string2(joycec, len = 25))
user system elapsed
1.36 0.00 1.39
> result
[1] " Hoopsa boyaboy hoopsa!"
ADDED
Although I developed my answer before having seen BrodieG's, as he points out they are very similar to each other. I have added some features of his to the above to get the solution below and tried the tests again. Unfortunately when I added the variation of his code the James Joyce example no longer works although it does work on the other two examples shown. The problem seems to be in adding the len constraint to the code and may represent a fundamental advantage of the code above (i.e. it can handle such a constraint and such constraints may be essential for very long strings).
find.string2 <- function(string, th = 3, len = floor(nchar(string)/th)) {
pat <- paste0(c("(.", "{1,", len, "})", rep("\\1", th-1)), collapse = "")
r <- regexpr(pat, string, perl = TRUE)
ifelse(r > 0, substring(string, r, r + attr(r, "capture.length")-1), "")
}
> find.string2("a0cc0vaaaabaaaabaaaabaa00bvw")
[1] "aaaab"
> find.string2("ff00f0f0f0f0f0f0f0f0000")
[1] "0f0f"
> system.time(result <- find.string2(joycec, len = 25))
user system elapsed
0 0 0
> result
[1] "w"
REVISED The James Joyce test that was supposed to be testing find.string2 was actually using find.string. This is now fixed.
Not optimized (even it is fast) function , but I think it is more R way to do this.
Get all patterns of certains length > threshold : vectorized using mapply and substr
Get the occurrence of these patterns and extract the one with maximum occurrence : vectorized using str_locate_all.
Repeat 1-2 this for all lengths and tkae the one with maximum occurrence.
Here my code. I am creating 2 functions ( steps 1-2) and step 3:
library(stringr)
ss = "ff00f0f0f0f0f0f0f0f0000"
ss <- "a0cc0vaaaabaaaabaaaabaa00bvw"
find_pattern_length <-
function(length=1,ss){
patt = mapply(function(x,y) substr(ss,x,y),
1:(nchar(ss)-length),
(length+1):nchar(ss))
res = str_locate_all(ss,unique(patt))
ll = unlist(lapply(res,length))
list(patt = patt[which.max(ll)],
rep = max(ll))
}
get_pattern_threshold <-
function(ss,threshold =3 ){
res <-
sapply(seq(threshold,nchar(ss)),find_pattern_length,ss=ss)
res[,which.max(res['rep',])]
}
some tests:
get_pattern_threshold('ff00f0f0f0f0f0f0f0f0000',5)
$patt
[1] "0f0f0"
$rep
[1] 6
> get_pattern_threshold('ff00f0f0f0f0f0f0f0f0000',2)
$patt
[1] "f0"
$rep
[1] 18
Since you want at least three repetitions, there is a nice O(n^2) approach.
For each possible pattern length d cut string into parts of length d. In case of d=5 it would be:
a0cc0
vaaaa
baaaa
baaaa
baa00
bvw
Now look at each pairs of subsequent strings A[k] and A[k+1]. If they are equal then there is a pattern of at least two repetitions. Then go further (k+2, k+3) and so on. Finally you also check if suffix of A[k-1] and prefix of A[k+n] fit (where k+n is the first string that doesn't match).
Repeat it for each d starting from some upper bound (at most n/3).
You have n/3 possible lengths, then n/d strings of length d to check for each d. It should give complexity O(n (n/d) d)= O(n^2).
Maybe not optimal but I found this cutting idea quite neat ;)
For a bounded pattern (i.e not huge) it's best I think to just create all possible substrings first and then count them. This is if the sub-patterns can overlap. If not change the step fun in the loop.
pat="a0cc0vaaaabaaaabaaaabaa00bvw"
len=nchar(pat)
thr=3
reps=floor(len/2)
# all poss strings up to half length of pattern
library(stringr)
pat=str_split(pat, "")[[1]][-1]
str.vec=vector()
for(win in 2:reps)
{
str.vec= c(str.vec, rollapply(data=pat,width=win,FUN=paste0, collapse=""))
}
# the max length string repeated more than 3 times
tbl=table(str.vec)
tbl=tbl[tbl>=3]
tbl[which.max(nchar(names(tbl)))]
aaaabaa
3
NB Whilst I'm lazy and append/grow the str.vec here in a loop, for a larger problem I'm pretty sure the actual length of str.vec is predetermined by the length of the pattern if you care to work it out.
Here is my solution, it's not optimized (build vector with patterns <- c() ; pattern <- c(patterns, x) for example) and can be improve but simpler than yours, I think.
I can't understand which pattern exactly should (I just return the max) be returned but you can adjust the code to what you want exactly.
str <- "a0cc0vaaaabaaaabaaaabaa00bvw"
findPatternMax <- function(str){
nb <- nchar(str):1
length.patt <- rev(nb)
patterns <- c()
for (i in 1:length(nb)){
for (j in 1:nb[i]){
patterns <- c(patterns, substr(str, j, j+(length.patt[i]-1)))
}
}
patt.max <- names(which(table(patterns) == max(table(patterns))))
return(patt.max)
}
findPatternMax(str)
> findPatternMax(str)
[1] "a"
EDIT :
Maybe you want the returned pattern have a min length ?
then you can add a nchar.patt parameter for example :
nchar.patt <- 2 #For a pattern of 2 char min
nb <- nb[length.patt >= nchar.patt]
length.patt <- length.patt[length.patt >= nchar.patt]

Haskell Ending Loop Return

I am trying to stop my program from stopping after the loop in a function ends. Let me first give some background - After a recent failed attempt at Haskell (Here) i have been working through a number of tutorials and have been able to successfully create myself lists containing both a name and priority (Below, working Code - Apologies if the copy/paste has miss-indented it).
module Main where
-- Function Main, gather details, then print
main :: IO ()
main = do info <- gatherInfo
let names = info
putStrLn . unlines . map printDetails $ names
-- Function to Get the Info
gatherInfo :: IO [(String, Int)]
gatherInfo = do putStr "Name: "
name <- getLine
if name == "quit"
then return []
else do priority <- getPri
let info = (name,priority)
otherInfo <- gatherInfo
return $ info : otherInfo
-- Function to get Priority
getPri :: IO Int
getPri = do putStr "Priority: "
input <- getLine
let parsed = reads input
if parsed == []
then do putStrLn "Incorrect Entry, please enter again"
getPri
else return $ fst $ parsed !! 0
--Function to print each detail
printDetails :: (String, Int) -> String
printDetails (name, priorityScore) = "Name: " ++ name ++ "Priority: " ++ show priorityScore
This code will print the following output(incl user input):
Patient Name: test1
Patient Priority: 1
Patient Name: test2
Patient Priority: 2
Patient Name: quit
Patient name: test1 Priority: 1
Patient name: test2 Priority: 2
As you can see, the list items are entered and then upon entering 'quit' the code prints the list contents.
The problem i have is that upon entering 'quit' and printing the list items, when i enter back into the program the items have gone.
What i am trying to achieve is running the gatherInfo function, then printing the list (in its entirety) and then going back to the gatherInfo function to add another item. For example, my output may be like:
Patient Name: test1
Patient Priority: 1
Patient name: test1 Priority: 1
Patient Name: test2
Patient Priority: 2
Patient name: test1 Priority: 1
Patient name: test2 Priority: 2
Patient Name: quit (Quit program, doesn't matter what happens now)
I have made several attempts at implementing this; for example, calling my printDetails function during each gatherInfo loop to print 'info', but with little success. How can i implement this into my design?
I suggest you do this:
Modify your gather info function so it takes info of only one patient.
Then create another function, let's call it main':
main' patients = do patient <- gatherInfo
if (fst patient == "quit")
then return ()
else do
let patients' = patient:patients -- add patient to list of patients
putStrLn . unlines . map printDetails $ patients' -- print list of patients
main' patients' -- continue
What are we doing here is remembering state of your program by passing parameter (this is how it is done in Haskell, as you have no states).
Now your main function would look like this:
main = main' [] -- start with empty list of patients
You may notice that I presumed your function gatherInfo will return patient with name "quit" when user inputs "quit", however you can do that some other way

How do I get to haskell to output numbers NOT in scientific notation?

I have a some items that I want to partition in to a number of buckets, such that each bucket is some fraction larger than the last.
items = 500
chunks = 5
increment = 0.20
{- find the proportions -}
sizes = take chunks (iterate (+increment) 1)
base = sum sizes / items
buckets = map (base *) sizes
main = print buckets
I'm sure there is a mathematically more elegant way to do this, but that's not my question.
The end step is always printing out in scientific notation.
How do I get plain decimal output? I've looked at the Numeric package but I'm getting nowhere fast.
> putStrLn $ Numeric.showFFloat Nothing 1e40 ""
10000000000000000000000000000000000000000.0
Try printf. e.g.:
> import Text.Printf
> printf "%d\n" (23::Int)
23
> printf "%s %s\n" "Hello" "World"
Hello World
> printf "%.2f\n" pi
3.14

Resources