I have an assignment, that I need to solve in Haskell.
It was firstly solved in C++, then I rewrote the code to Haskell.
The algorithm is working correctly but the Haskell version runs slower, compared to the C++ version.
For example, for the input:
110110100011010101010101
010101101001000101010100
Haskell (with GHCI): 20 sec
Haskell (compiled GHC): 3 sec
C++: <1 sec
With a difference this much, I think, I am doing something wrong.
Problem description: We are given 2 arrays(strings) of the same length, containing 0s and 1s. Our task is to find the minimal switches(switch=0->1 or 1->0) to make the source array identical to the target. There is a rule for switching: We can only change the state of i if i+1 is 1 AND i+2->n are 0, except for the last one.
C++ code:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
//flips the i-th char int s to match the i-th char in t
int flip2(int i, string& s, char t){
if(i>=s.length() || s[i]==t) return 0; //if matches, or non-existent index, returns 0 steps
int c=1; // 1 step is switching the character
c+=flip2(i+1,s,'1'); //in order to switch i, i+1 have to be 1
for(int j=i+2;j<s.length();j++) //in order to switch i, i+2->n have to be 0
c+=flip2(j,s,'0');
s[i]=t;
return c;
}
//returns the minimum number of switch steps to make s=t
int ultimateFlip( string s, string t){
int c=0;
for(int i=0;i<s.length();i++){ // switches every character in s to match t
c+=flip2(i,s,t[i]); //adds up the steps
}
return c;
}
int main()
{
string s; // source array (made up of 0s and 1s)
getline(cin, s);
string t; //target array (made up of 0s and 1s)
getline(cin, t);
cout<<ultimateFlip(s,t);
}
Haskell code:
import System.IO
import Control.Monad
main :: IO ()
main = do
hSetBuffering stdout NoBuffering
s <- getLine -- source string
t <- getLine -- target string
let sol = ultimateFlip s t
putStrLn $ show sol
return ()
--returns the minimum number of switch steps to make s=t
ultimateFlip :: [Char] -> [Char] -> Int
ultimateFlip [] [] = 0
ultimateFlip (s:sx) (t:tx) = k + ultimateFlip sxn tx
where
(k,sxn)=flip2 s t sx --snx = new (after) version of sx(the rest of the string)
--flips the s to match t, sx= rest of the source string after s
flip2 :: Char->Char->[Char]->(Int,[Char])
flip2 s t sx
| s == t = (0,sx) --if mathes, no switch needed
| null sx = (1,sx) --if last one, one switch need
| otherwise = (k2+k1+1,'1':nsx2)
where
(sxh:sxt) = sx
(k1,nsx1) = flip2 sxh '1' sxt --switch next to 1
(k2,nsx2) = zeroOut nsx1 --switch everything after the next to 0
--switch everything to 0
zeroOut :: [Char] -> (Int, [Char])
zeroOut [] = (0,[])
zeroOut (s:sx) = (k1+k2,'0':nsx2)
where
(k1,nsx1) = flip2 s '0' sx
(k2,nsx2) = zeroOut nsx1
For Haskell I am using: GHC, version 8.10.2
For C++ I am using: gcc (GCC) 10.2.0
You are spending an awful lot of time allocating and immediately destructuring pairs. That's pretty unnecessary, because you always know what [Char] you're going to get back in the second half of the tuple. Here's one way to eliminate that problem:
ultimateFlip :: [Char] -> [Char] -> Int
ultimateFlip [] [] = 0
ultimateFlip (s:sx) (t:tx)
| s == t = ultimateFlip sx tx
| null sx = 1
| otherwise = ultimateFlip sx tx' + 1 + ultimateFlip tx' tx where
tx' = '1' : ('0'<$drop 1 tx)
With this change, the Haskell performs pretty much the same as the C++ on my machine -- sometimes a few ms faster, sometimes a few ms slower, for inputs slightly longer than the one you proposed.
Of course, as usual, switching to a better algorithm blows microoptimizations like this one out of the water in terms of gains. The following implementation takes less time than the reporting precision of time even for much longer strings.
import Data.Bits
main :: IO ()
main = do
s <- getLine
t <- getLine
print (ultimateFlip s t)
ultimateFlip :: [Char] -> [Char] -> Int
ultimateFlip [] [] = 0
ultimateFlip (s:sx) (t:tx)
| s == t = ultimateFlip sx tx
| otherwise = go '1' pow sx + 1 + go '1' pow tx where
pow = 2^(length sx-1)
go _ _ [] = 0
go s pow (t:tx) = go s' pow' tx + n where
pow' = shiftR pow 1
(s', n) = if s == t then ('0', 0) else ('1', pow)
It also smoothly upgrades to using arbitrary-sized integers for those longer inputs just by switching Int to Integer in the type signature of ultimateFlip.
The biggest problem you're having is with a lack of "strictness". Haskell's lazy evaluation means that even simple calculations like k2+k1+1 generally won't be evaluated until the answer is needed. With recursive functions performing a series of additions like thus, you can sometimes end up building an enormous unevaluated expression that takes up tons of memory before it finally gets evaluated at the end.
Here, by adding a language extension at the top:
{-# LANGUAGE BangPatterns #-}
and adding a single strictness "!" annotation in your flip's "where" clause:
(!k1,nsx1) = flip2 sxh '1' sxt
^
this drops the runtime on my machine from 800ms to 80ms (again, compiled with ghc -O2). That's still slower than the C++ version (20ms), but it's in the right ballpark.
The annotation here has the effect of forcing the expression to be evaluated. Figuring out where strictness annotations are needed is a bit of a dark art. In this case, I suspected your counting was causing the problem, so I threw in "!" before all the places that a count was being returned, and then I deleted them until I found the one that made most of the difference.
The remaining speed difference is probably a result of using a lot of list processing in Haskell (versus arrays in C++), so you could likely do better, though I'm not sure it's worth the trouble.
Related
New to OCaml and Functional Programming as a whole so I was having some problems with keeping the type ambiguous. I'm trying to make a function which takes in a symbol accum(which looks like (+) or (-.) or (*) etc.) and a function f. My current implementation is below and if let's say I passed in (** f (x) = 3x^2 + 5x + 6 **) but I always get '6' instead of '276' because in the else part I'm not summing adding the results of the previous rounds so I just get the final value of '6'.
I get type errors because of the + so when I throw floats in it breaks. How can I overcome this (let partial accept floats or ints but actually accumulate the answer)?
let rec powerSum(sign )(f):'a =
fun x ->
if x = 0 then
f (x)
else if x < 0 then
raise(Failure "Error arg isn't '+'")
else
powerSum sign f (x-1);
Hint: you should use accum at some point.
Having trouble writing a power function inStandard Ml. Im trying to write a function called exp of type int -> int -> int.
The application exp b e, for non-negative e, should return b^e.
For example, exp 3 2 should return 9. exp must be implemented with the function compound provided below. exp should not directly calls itself. Here is the compound function, it takes in a value n, a function, and a value x. All it does is it applies the function to the value x n number of times.
fun compound 0 f x = x
| compound n f x = compound (n-1) f (f x);
Im having trouble figuring out how to write this function without recursion, and with the restraint of having to use a function that only can use a function with one parameter. Anyone have any ideas of where to start with this?
This is what I have:
fun exp b 0 = 1
| exp b e = (compound e (fn x => x*x) b)
I know that this doesn't work, since if i put in 2^5 it will do:
2*2, 4*4, 16*16 etc.
You are extremely close. Your definition of exp compounds fn x => x*x which (as you noticed) is not what you want, because it is repeatedly squaring the input. Instead, you want to do repeated multiplication by the base. That is, fn x => b*x.
Next, you can actually remove the special case of e = 0 by relying upon the fact that compound "does the right thing" when asked to apply a function 0 times.
fun exp b e = compound e (fn x => b*x) 1
You could just do this instead I believe
fun exp 0 0 = 1
| exp b 0 = 1
| exp b e = (compound (e - 1) (fn x => b * x ) b);
this may not be exactly 100% proper code. I sort of just now read a bit of Standard ML documentation and took some code and reworked it for your example but the general idea is the same for most programming languages.
fun foo (num, power) =
let
val counter = ref power
val total = 1
in
while !counter > 0 do (
total := !total * num
counter := !counter - 1
)
end;
To be more clear with some pseudo-code:
input x, pow
total = 1
loop from 1 to pow
total = total * x
end loop
return total
This doesn't handle negative exponents but it should get you started.
It basically is a simple algorithm of what exponents truly are: repeated multiplication.
2^4 = 1*2*2*2*2 //The 1 is implicit
2^0 = 1
I have this code in VBA (looping through the array a() of type double):
bm = 0 'tot
b = 0 'prev
For i = 24 To 0 Step -1
BP = b 'prevprev = prev
b = bm 'prev = tot
bm = T * b - BP + a(i) 'tot = a(i) + T * prev - prevprev
Next
p = Exp(-xa * xa) * (bm - BP) / 4 '* (tot - prevprev)/4
I'm putting this in F#. Clearly I could use an array and mutable variables to recreate the VBA. And maybe this is an example of the right time to use mutable that I've seen hinted at. But why not try to do it the most idiomatic way?
I could write a little recursive function to replicate the loop. But it kind of feels like littering to hang out a little sub-loop that has no meaning on its own as a standalone, named function.
I want to do it with List functions. I have a couple ideas, but I'm not there yet. Anyone get this in a snap??
The two vague ideas I have are: 1. I could make two more lists by chopping off one (and two) elements and adding zero-value element(s). And combine those lists. 2. I'm wondering if a list function like map can take trailing terms in the list as arguments. 3. As a general question, I wonder if this might be a case where an experienced person would say that this problem screams for mutable values (and if so does that dampen my enthusiasm for getting on the functional boat).
To give more intuition for the code: The full function that this is excerpted from is a numerical approximation for the cumulative normal distribution. I haven't looked up the math behind this one. "xa" is the absolute value of the main function argument "x" which is the number of standard deviations from zero. Without working through the proof, I don't think there's much more to say than: it's just a formula. (Oh and maybe I should change the variable names--xa and bm etc are pretty wretched. I did put suggestions as comments.)
It's just standard recursion. You make your exit condition and your recur condition.
let rec calc i prevPrev prev total =
if i = 0 then // exit condition; do your final calc
exp(-xa * xa) * (total - prevPrev) / 4.
else // recur condition, call again
let newPrevPrev = prev
let newPrev = total
let newTotal = (T * newPrev - newPrevPrev + a i)
calc (i-1) newPrevPrev newPrev newTotal
calc 24 initPrevPrev initPrev initTotal
or shorter...
let rec calc i prevPrev prev total =
if i = 0 then
exp(-xa * xa) * (total - prevPrev) / 4.
else
calc (i-1) prev total (T * total - prev + a i)
Here's my try at pulling the loop out as a recursive function. I'm not thrilled about the housekeeping to have this stand alone, but I think the syntax is neat. Aside from an error in the last line, that is, where the asterisk in (c * a.Tail.Head) gets the red squiggly for float list not matching type float (but I thought .Head necessarily returned float not list):
let rec RecurseIt (a: float list) c =
match a with
| []-> 0.0
| head::[]-> a.Head
| head::tail::[]-> a.Head + (c * a.Tail) + (RecurseIt a.Tail c)
| head::tail-> a.Head + (c * a.Tail.Head) - a.Tail.Tail.Head + (RecurseIt a.Tail c)
Now I'll try list functions. It seems like I'm going to have to iterate by element rather than finding a one-fell-swoop slick approach.
Also I note in this recursive function that all my recursive calls are in tail position I think--except for the last one which will come one line earlier. I wonder if this creates a stack overflow risk (ie, prevents the compiler from treating the recursion as a loop (if that's the right description), or if I'm still safe because the algo will run as a loop plus just one level of recursion).
EDIT:
Here's how I tried to return a list instead of the sum of the list (so that I could use the 3rd to last element and also sum the elements), but I'm way off with this syntax and still hacking away at it:
let rec RecurseIt (a: float list) c =
match a with
| []-> []
| head::[]-> [a.Head]
| head::tail::[]-> [a.Head + (c * a.Tail)] :: (RecurseIt a.Tail c)
| head::tail-> [a.Head + (c * a.Tail.Head) - a.Tail.Tail.Head] :: (RecurseIt a.Tail c)
Here's my try at a list function. I think the problem felt more complicated than it was due to confusing myself. I just had some nonsense with List.iteri here. Hopefully this is closer to making sense. I hoped some List. function would be neat. Didn't manage. For loop not so idiomatic I think. :
for i in 0 .. a.Length - 1 do
b::
a.Item(i) +
if i > 0 then
T * b.Item(i-1) -
if i > 1 then
b.Item(i-2)
else
0
else
0
I want to write this simple code :
let rec gcd a b =
if b = 0 then a else gcd b (a mod b);;
val gcd : int -> int -> int = <fun>
Printf.printf "%d da \n" gcd 55 200 ;;
This is the code , the error I get is :
File "tst.ml", line 3, characters 0-3:
Error: Syntax error
And also , can anyone explain to me what is that " int -> int -> int = " all about ? I know that it must be something about the parameters and the returned value of the function but what and how ? :)
You're passing gcd 55 and 200 as separate parameters of printf. So, try this:
Printf.printf "%d da\n" (gcd 55 200);;
It looks like you did some copy & paste from an ocaml interactive session, since normally we don't mix up function definitions (the 2 first lines), and function declarations (the third line, though in this case it looks more like the answer of the ocaml interpreter when provided with the definition - because of the <fun> part which isn't syntactically correct in a program, but is used by the interpreter to indicate that it figured out that the value is a function) in the same scope.
So, you should not include that third line, and you will have to fix the last instruction, as #JeffreyScofield explained.
(* gcd function definition *)
let rec gcd a b =
if b = 0 then a else gcd b (a mod b);;
(* val gcd: int -> int -> int *)
Printf.printf "%d da \n" (gcd 55 200);;
Alternatively, the last line could be written:
Printf.printf "%d da \n" ## gcd 55 200;;
The function signature you included by mistake indicates that gcd takes a sequence of 2 integer parameters, and returns an integer. The notation is said to be in curried form: each parameter passed to a function A yields another function B expecting the remaining parameters of A. Thus you can read that signature several ways:
As a function taking 2 integers and returning one,
val gcd: int -> int -> int
As a function taking an integer, and returning an a function, which takes an integer and returns an integer.
val gcd: int -> (int -> int)
Both notations are equivalent (The arrow "operator" is said to be associative on the right), but the second one helps to understand this idea of function return "chaining".
In int -> int -> int:
The last int is the return value
The first two ints are the parameters
Consider reading this to understand function types.
I'm very new to OCaml / functional programming, and I'm confused about the implementation of some things that are relatively simple other languages I know. I could use any and all help.
Chiefly: in a program I'm working on, I either increment or decrement a variable based on a certain parameter. Here's something representative of what I have:
let tot = ref 0 in
for i = 0 to s do
if test_num > 0 then
tot := !tot + other_num
else
tot := !tot - other_num
done;;
This is obviously not the way to go about it, because even if the else statement is never taken, the code acts as if it is, each and every time, presumably because it's closer to the bottom of the program? I know OCaml has pretty sophisticated pattern matching, but within this level of coed I need access to a handful of lists I've already created, and, as far as I understand, I can't access those lists from a top-level function without passing them all as parameters.
I know I'm going about this the wrong way, but I have no idea how to do this idiomatically.
Suggestions? Thanks.
edit
Here's a more concise example:
let ex_list = [1; -2; 3; -4] in
let max_mem = ref 0 in
let mem = ref 0 in
let () =
for i = 0 to 3 do
let transition = List.nth ex_list i in
if transition > 0 then (
mem := (!mem + 10);
) else
mem := (!mem - 1);
if (!mem > !max_mem) then (max_mem := !mem);
done;
print_int !max_mem; print_string "\n";
in !mem;
At the end, when I print max_mem, I get 19, though this value should be (0 + 10 - 1 + 10 - 1 = 18). Am I doing the math wrong, or does the problem come from somewhere else?
Your code looks fine to me. It doesn't make a lot of sense as actual code, but I think you're just trying to show a general layout. It's also written in imperative style, which I usually try to avoid if possible.
The if in OCaml acts just like it does in other languages, there's no special thing about being near the bottom of the program. (More precisely, it acts like the ? : ternary operator from C and related languages; i.e., it's an expression.)
Your code doesn't return a useful value; it always returns () (the quintessentially uninteresting value known as "unit").
If we replace your free variables (ones not defined in this bit of code) by constants, and change the code to return a value, we can run it:
# let s = 8 in
let other_num = 7 in
let test_num = 3 in
let tot = ref 0 in
let () =
for i = 0 to s do
if test_num > 0 then
tot := !tot + other_num
else
tot := !tot - other_num
done
in
!tot;;
- : int = 63
#
If you're trying to learn to write in a functional style (i.e., without mutable variables), you would write this loop as a recursive function and make tot a parameter:
# let s = 8 in
let other_num = 7 in
let test_num = 3 in
let rec loop n tot =
if n > s then
tot
else
let tot' =
if test_num > 0 then tot + other_num else tot - other_num
in
loop (n + 1) tot'
in
loop 0 0;;
- : int = 63
It would probably be easier to help if you gave a (edited to add: small :-) self-contained problem that you're trying to solve.
The other parts of your question aren't clear enough to give any advice on. One thing that I might point out is that it's completely idiomatic to use pattern matching when processing lists.
Also, there's nothing wrong with passing things as parameters. That's why the language is called "functional" -- your code consists of functions, which have parameters.
Update
I like to write let () = expr1 in expr2 instead of expr1; expr2. It's just a habit I got into, sorry if it's confusing. The essence is that you're evaluating the first expression just for its side effects (it has type unit), and then returning the value of the second expression.
If you don't have something after the for, the code will evaluate to (), as I said. Since the purpose of the code seems to be to compute the value of !tot, this is what I returned. At the very least, this lets you see the calculated value in the OCaml top level.
tot' is just another variable. If you calculate a new value straightforwardly from a variable named var, it's conventional to name the new value var'. It reads as "var prime".
Update 2
Your example code works OK, but it has the problem that it uses List.nth to traverse a list, which is a slow (quadratic) operation. In fact your code is naturally considered a fold. Here's how you might write it in a functional style:
# let ex_list = [1; -2; 3; -4] in
let process (tot, maxtot) transition =
let tot' = if transition > 0 then tot + 10 else tot - 1 in
(tot', max maxtot tot')
in
List.fold_left process (0, 0) ex_list;;
- : int * int = (18, 19)
#
In addition to Jeffrey's answer, let me second that this is not how you would usually write such code in Ocaml, since it is a very low-level imperative approach. A more functional version would look like this:
let high ex_list =
let deltas = List.map (fun x -> if x > 0 then 10 else -1) ex_list in
snd (List.fold_left (fun (n, hi) d -> (n+d, max (n+d) hi)) (0, 0) deltas)
let test = high [1; -2; 3; -4]