So I recently learned sml and really confused on how to use it compared to java. So I was told me make a code that takes consecutive pairs of values, adding them and inserting the sums into a new list.
If the original list has an odd length, then the first n-1 items are pairwise added, and the n-th item is simply copied as is at the end of the new list.
So my code so far is:
fun sumpairs x =
if null x then []
else (if (tl x =[]) then x
else hd x + hd(tl x) :: sumpairs(tl (tl x));
sumpairs([1,2,3]); (I want to test it on this to get something like [3,3])
but I'm getting a syntax error. And since the sml doesn't find the error for me I'm lost on what the problem or if it even works or not. I believe that is should work.
You have an unmatched parenthesis in (if (tl x =[]).
(SML's error messages are possibly the most confusing I've encountered - I get "syntax error at EOF", which is completely useless.)
It's easier to match parentheses if you use fewer:
fun sumpairs x =
if null x then []
else if tl x = [] then x
else hd x + hd (tl x) :: sumpairs (tl (tl x))
An editor that can show which parentheses match also helps.
Most modern programmer's editors can do that, if you find the magic setting.
I would recommend that you get comfortable with pattern matching - it's usually much easier to follow the logic with patterns than with a chain of conditionals:
fun sumpairs [] = []
| sumpairs [x] = [x]
| sumpairs (x::y::xs) = x + y :: sumpairs xs
Related
I have an if-else statement, and in the else block I want it to first recurse to the function, except for the last two elements of the list, and then return two elements.
In the following function, after the if-else statement, I have 2 lines of code. however this doesnt compile. I believe the compiler reads these two lines as a single line of code. How do you fix that?
doubleEveryOther :: [Integer] -> [Integer] --outputs the input list, but every 2nd element(from the right) is doubled
doubleEveryOther [] = []
doubleEveryOther x = if (length x <2)
then
x
else
doubleEveryOther init (init x) -- These two lines
[2*last(init x), last x] -- These two lines
The compiler says:
* Couldn't match expected type: [Integer]
with actual type: [a0] -> [a0]
* Probable cause: `init' is applied to too few arguments
In the first argument of `doubleEveryOther', namely `init'
In the expression: doubleEveryOther init (init x)
In the expression:
[doubleEveryOther init (init x), 2 * last (init x), last x]
|
19 | [doubleEveryOther init (init x), 2*last(init x), last x]
|
You can not return two lists. If you have two results you want to combine, you use some function, like (++) :: [a] -> [a] -> [a].
That being said, you here don't need this. You can work with simple pattern matching:
doubleEveryOtherFromLeft :: Num a => [a] -> [a]
doubleEveryOtherFromLeft (x:y:xs) = 2*x : y : doubleEveryOtherFromLeft xs
doubleEveryOtherFromLeft xs = xs
then our doubleEveryOther can reverse the list twice:
doubleEveryOther:: Num a => [a] -> [a]
doubleEveryOther = reverse . doubleEveryOtherFromLeft . reverse
I think you are just missing the append operator ++:
doubleEveryOther (init (init x))
++ [2 * last (init x), last x]
I have an if-else statement, and in the else block I want it to first
recurse to the function, except for the last two elements of the list,
and then return two elements
OK. I sort of understand what you're doing. The function name is good - the best name is verb-noun, here doubleEveryOther. However, the code looks a lot like Lisp, probably Scheme - the repeated use of init gives it away. That's not how you write Haskell. (I also write Lisp in Haskell syntax too much...)
Haskell recursion works using pattern matching.
lst = [2,3,4]
1 : [2,3,4] -- [1,2,3,4]
lst = [1,2,3,4]
(x:xs) = lst -- x is 1, xs = [2,3,4]
So, in this case, you want to match your list against x:y:xs:
lst = [1,2,3,4]
(x:y:xs) = lst -- x is 1, y is 2, xs=[3,4]
Hence:
doubleEveryOther :: Num a => [a] -> [a]
doubleEveryOther [] = []
doubleEveryOther [x] = [2*x]
doubleEveryOther (x:y:xs) = (2*x):doubleEveryOther xs
Please note the number of special cases which need to be handled. If I am given an empty list, I should return an empty list. If I am given a single value, I need to double it (in analogy to your if .. else clause). If I am given two or more values, this matches x=first, y=second, xs=[] or more.
As for returning more than one value, you can return only one thing from a function. It can be a single value, a single tuple, a single list, and so on.
In this case, you have written a function which says doubleEveryOther - good - but then you want to return the last two values unchanged. You would be better taking off the last two values, running the simple doubleEveryOther and then bolting the last two values on the end. Otherwise, you are overburdening your function.
I am taking the Programming Languages course offered by Washington University, during one of the lectures, this code popped up worked for professor Dan, however, I am getting unbound variable or constructor:valof error. Could not figure it out.
it is smlnj, and running on emacs, if it would yield any help.
fun max1(xs: int list)=
if null xs
then NONE
else
let val tl_ans = max1(tl xs)
in if isSome tl_ans andalso valof tl_ans > hd xs
then tl_ans
else SOME (hd xs)
end
here is the error: options.sml:7.37-7.42 Error: unbound variable or constructor: valof
As quoify says, it's spelled valOf.
And as kopecs says, if you use pattern matching, it will be much shorter:
fun max1 (x::y::rest) = max1 (Int.max (x, y) :: rest)
| max1 [x] = SOME x
| max1 [] = NONE
(This version also uses the library function Int.max for added brevity.)
If this is too compact, you could also write:
fun max1 (x::y::rest) = let val z = Int.max (x, y) in max1 (z::rest) end
| max1 [x] = SOME x
| max1 [] = NONE
The version from the slides deals with an annoying situation that arises in many recursive functions that return sum types like 'a option: You may need to perform a call, do some unpacking (i.e. remove SOME), and then pack the result back (i.e. add SOME again).
But the max1 problem does not necessitate that situation.
I'm trying to learn haskell by solving some online problems and training exercises.
Right now I'm trying to make a function that'd remove adjacent duplicates from a list.
Sample Input
"acvvca"
"1456776541"
"abbac"
"aabaabckllm"
Expected Output
""
""
"c"
"ckm"
My first though was to make a function that'd simply remove first instance of adjacent duplicates and restore the list.
module Test where
removeAdjDups :: (Eq a) => [a] -> [a]
removeAdjDups [] = []
removeAdjDups [x] = [x]
removeAdjDups (x : y : ys)
| x == y = removeAdjDups ys
| otherwise = x : removeAdjDups (y : ys)
*Test> removeAdjDups "1233213443"
"122133"
This func works for first found pairs.
So now I need to apply same function over the result of the function.
Something I think foldl can help with but I don't know how I'd go about implementing it.
Something along the line of
removeAdjDups' xs = foldl (\acc x -> removeAdjDups x acc) xs
Also is this approach the best way to implement the solution or is there a better way I should be thinking of?
Start in last-first order: first remove duplicates from the tail, then check if head of the input equals to head of the tail result (which, by this moment, won't have any duplicates, so the only possible pair is head of the input vs. head of the tail result):
main = mapM_ (print . squeeze) ["acvvca", "1456776541", "abbac", "aabaabckllm"]
squeeze :: Eq a => [a] -> [a]
squeeze (x:xs) = let ys = squeeze xs in case ys of
(y:ys') | x == y -> ys'
_ -> x:ys
squeeze _ = []
Outputs
""
""
"c"
"ckm"
I don't see how foldl could be used for this. (Generally, foldl pretty much combines the disadvantages of foldr and foldl'... those, or foldMap, are the folds you should normally be using, not foldl.)
What you seem to intend is: repeating the removeAdjDups, until no duplicates are found anymore. The repetition is a job for
iterate :: (a -> a) -> a -> [a]
like
Prelude> iterate removeAdjDups "1233213443"
["1233213443","122133","11","","","","","","","","","","","","","","","","","","","","","","","","","","",""...
This is an infinite list of ever reduced lists. Generally, it will not converge to the empty list; you'll want to add some termination condition. If you want to remove as many dups as necessary, that's the fixpoint; it can be found in a very similar way to how you implemented removeAdjDups: compare neighbor elements, just this time in the list of reductions.
bipll's suggestion to handle recursive duplicates is much better though, it avoids unnecessary comparisons and traversing the start of the list over and over.
List comprehensions are often overlooked. They are, of course syntactic sugar but some, like me are addicted. First off, strings are lists as they are. This functions could handle any list, too as well as singletons and empty lists. You can us map to process many lists in a list.
(\l -> [ x | (x,y) <- zip l $ (tail l) ++ " ", x /= y]) "abcddeeffa"
"abcdefa"
I don't see either how to use foldl. It's maybe because, if you want to fold something here, you have to use foldr.
main = mapM_ (print . squeeze) ["acvvca", "1456776541", "abbac", "aabaabckllm"]
-- I like the name in #bipll answer
squeeze = foldr (\ x xs -> if xs /= "" && x == head(xs) then tail(xs) else x:xs) ""
Let's analyze this. The idea is taken from #bipll answer: go from right to left. If f is the lambda function, then by definition of foldr:
squeeze "abbac" = f('a' f('b' f('b' f('a' f('c' "")))
By definition of f, f('c' "") = 'c':"" = "c" since xs == "". Next char from the right: f('a' "c") = 'a':"c" = "ac" since 'a' != head("c") = 'c'. f('b' "ac") = "bac" for the same reason. But f('b' "bac") = tail("bac") = "ac" because 'b' == head("bac"). And so forth...
Bonus: by replacing foldr with scanr, you can see the whole process:
Prelude> squeeze' = scanr (\ x xs -> if xs /= "" && x == head(xs) then tail(xs) else x:xs) ""
Prelude> zip "abbac" (squeeze' "abbac")
[('a',"c"),('b',"ac"),('b',"bac"),('a',"ac"),('c',"c")]
just recently I tried to write a program which basically simulates a simple system from an Online Game. The idea behind that is, to let the program calculate the most efficient set of items for the most possible stat efficiency from a set. To clarify this a bit more:
you've got 8 item Slots and 74 different items, you can't use any item twice, and it doesn't matter which item is in which slot. I'am not even yet trying to calculate one set of stats, I'am stuck way earlier!
So the problem with this is the number of possibilities which are (74^8) before filtering and (74 choose 8) after filtering.
My program already starts lagging when I just try head(permu' 2).
Since I know Haskell is supposed to work with infinite Lists, how does it work with a List of 899 trillion entries? Well I know obviously it takes a lot of capacity for the PC but that's why I am here to ask:
How do I treat a big List in Haskell so that I can work with it?
the function simplified looks like this:
quicksort :: (Ord a) => [a] -> [a]
quicksort [] = []
quicksort [a] = [a]
quicksort (x:xs) = (quicksort [y | y <- xs, y <= x]) ++ [x] ++ (quicksort [z | z <- xs , z > x])
eliminatedouble [] = []
eliminatedouble (x:xs) = if x `elem` xs then eliminatedouble xs else x:(eliminatedouble xs)
permu' n | n>8 = error "8 is max"
| otherwise = eliminatedouble (filter allSatisfied (generate n))
where
generate 0 = [[]]
generate x = [quicksort (a:xs) | a <- [1..74], xs <- generate (x-1)]
allSatisfied [] = True
allSatisfied (x:xs) = (checkConstraint x xs) && (allSatisfied xs)
checkConstraint x xs = not (doubled x xs)
doubled x xs = x `elem` xs
would be interesting to know how to do all this way cheaper.
Thanks in advance, regards.
You're making this much more difficult than it needs to be.
choose 0 xs = [[]]
choose n [] = []
choose n (x:xs) = map (x:) (choose (n-1) xs) ++ choose n xs
In my interpreter, choose 5 [1..74] takes about 22 seconds to compute all the entries and choose 6 [1..74] takes 273 seconds. Additionally, choose 8 [1..74] starts chugging through combinations straight away; I estimate that it would take about 6 hours to generate them all. N.B. that this is in the interpreter, with no optimization or other fanciness going on; possibly it could go much faster if you give GHC a chance to figure out how.
Assuming that you intend to do some nontrivial computation on each element of choose 8 [1..74], I suggest you either schedule a largish chunk of time or else think about solutions that do not do an exhaustive search -- perhaps using some heuristics to get an approximate answer, or figuring out how to do some pruning to cut out large, uninteresting swaths of the search space.
I dont know what is wrong with my code, I just want to get a list and fill it up properly and return that list as a result of that function. could you help me to solve this problem?
fill [] counter= []
fill (x:xs) counter= do
(if x==0
then do
let new =counter+1
new:xs
fill xs new
else
fill xs counter)
I want to fill the zeros with non repeated numbers
main = do
fill [9,0,9,0,0,0] 0 -- expexted to get [9,1,9,2,3,4]
You are writing Haskell as if it's an imperative language. The second expression in the do block, new:xs, does nothing at all.
The do block after then
do
let new =counter+1
new:xs
fill xs new
Because dos and lets actually translate to lambdas:
let x = a
b x
becomes
(\x -> b x)(a)
, your do block translates to:
(\new -> (\discarded -> fill xs new)(new:xs) ) (counter + 1)
and new:xs is discarded in the middle.
Do notation is only useful if you are dealing with monads. Otherwise, it leads to misleading code.
See also:
https://en.wikibooks.org/wiki/Haskell/do_Notation
http://www.haskell.org/haskellwiki/Do_notation_considered_harmful
We could a bit modify original version:
fillZero' (z:zs) y'#(y:ys) =
if z == 0
then y : fillZero' zs ys
else z : fillZero' zs y'
fillZero' _ _ = []
and use:
fillZero = flip fillZero' [1..]
> fillZero [0,305,0,0,0,8,0,0]
[1,305,2,3,4,8,5,6]