I'm trying to create a length function, similar to the one already included in ML. My restrictions are that it has to be done on one line and use either map, foldl, or foldr.
Right now my line of code looks like this:
val mylength = foldr ( fn(x,y) => 1+y) 0;
I am by no means an expert at ML, but my reasoning so far is this:
To my understanding, foldr will, beginning at the last item in the list, pass it as the x argument in my function and use the 0 as the initial y value. It should then add 1 to the y value and basically ignore x. In theory, I believed this would give me my total length. However I am given the following error:
stdIn:136.5-136.37 Warning: type vars not generalized because of
value restriction are instantiated to dummy types (X1,X2,...)
val mylength = fn : ?.X1 list -> int
My big problem is figuring out how to create this function in a way that it can accept lists of any type.
If anyone could offer some advice about how to approach this problem I would appreciate it, perhaps I still haven't wrapped my head around ML's style of programming.
Your function is correct in essence. Depending on what interpreter you use, it will accept the given code or reject it. For instance, running your code on CloudML will do just fine.
To avoid this problem rather define it as a function like this:
fun mylength l = foldr ( fn(x,y) => 1+y) 0 l;
Daniel Grossman from the University of Washington explained in one of his lessons that this error has to do with mutable references. Regretfully, I can't recall exactly in which lesson he mentioned this.
You may consider the following in the meanwhile:
SML Warning: Type Vars Not Generalized when using Empty Lists or NONE option
Polymorphic function as return value and value restriction in SML
The value restriction
Given some standard definitions for foldl and foldr:
fun foldr f e [] = e
| foldr f e (x::xr) = f(x, foldr f e xr);
fun foldl f e [] = e
| foldl f e (x::xr) = foldl f (f(x, e)) xr;
One can manually apply your function to a short list and see how term rewriting unfolds:
foldr (fn(_,y) => 1+y) 0 [5,6,7]
(fn(_,y) => 1+y) (5,foldr (fn(_,y) => 1+y) 0 [6,7])
(fn(_,y) => 1+y) (5,(fn(_,y) => 1+y) (6,foldr (fn(_,y) => 1+y) 0 [7]))
(fn(_,y) => 1+y) (5,(fn(_,y) => 1+y) (6,(fn(_,y) => 1+y) (7,foldr (fn(_,y) => 1+y) 0 [])))
(fn(_,y) => 1+y) (5,(fn(_,y) => 1+y) (6,(fn(_,y) => 1+y) (7,0)))
(fn(_,y) => 1+y) (5,(fn(_,y) => 1+y) (6,1))
(fn(_,y) => 1+y) (5,2)
3
With foldr you can see that the the element 7 is resolved first (it folds from right to left) and that the length of the expression (and thus the stack memory) grows proportionally to the list. With foldl you can see that 5 is resolved first (it folds from left to right) and that the length of the expression is constant. In both cases the first part of the argument to the anonymous function is discarded.
foldl (fn(_,y) => 1+y) 0 [5,6,7]
foldl (fn(_,y) => 1+y) ((fn(_,y) => 1+y)(5, 0)) [6,7]
foldl (fn(_,y) => 1+y) 1 [6,7]
foldl (fn(_,y) => 1+y) ((fn(_,y) => 1+y)(6, 1)) [7]
foldl (fn(_,y) => 1+y) 2 [7]
foldl (fn(_,y) => 1+y) ((fn(_,y) => 1+y)(7, 2)) []
foldl (fn(_,y) => 1+y) 3 []
3
Admittedly, the lambdas clutter up the whole thing. Given the definition
fun plus1(_,y) = 1+y
The following rewriting is equivalent but more legible.
foldr plus1 0 [5,6,7]
plus1 (5, foldr plus1 0 [6,7])
plus1 (5, plus1 (6, foldr plus1 0 [7]))
plus1 (5, plus1 (6, plus1 (7, foldr plus1 0 [])))
plus1 (5, plus1 (6, plus1 (7, 0)))
plus1 (5, plus1 (6, 1))
plus1 (5, 2)
3
foldl plus1 0 [5,6,7]
foldl plus1 (plus1 (5,0)) [6,7]
foldl plus1 1 [6,7]
foldl plus1 (plus1 (6,1)) [7]
foldl plus1 2 [7]
foldl plus1 (plus1 (7,2)) []
foldl plus1 3 []
3
A slightly longer solution (which I came up with by trying to think how map could be relevant):
fun len xs = (foldr op+ 0 o map (fn x => 1)) xs;
Here o is the composition operator. I wanted to write
val len = foldr op+ 0 o map (fn x => 1);
so as to mimic the sort of point-free style popular in Haskell but ran into exactly the same value restriction that your original definition encountered.
Related
i have a list , and a tuple (start,end,interval)
i am trying to iterate over the list and return the elements that are in list from start to end with interval steps .
for example:
cutt [1,2,3,4,77,8,7] (1,5,2);
val it = [2,4,8] : int list;
the problem is that i can't use recursion ,
i was thinking to use foldl but the problem is how to skip over elements i don't want to use list.nth?
i would appriciate little hints ! thank you
It sounds like you need two functions. The first step is to retrieve a slice of your list between indices. This sounds suspiciously related to a solution posted very recently.
fun slice'(lst, start, stop) =
let
val (_, lst') = foldl
(fn (v, (idx, acc)) =>
if idx >= start andalso idx <= stop then
(idx + 1, v::acc)
else
(idx + 1, acc))
(0, [])
lst
in
List.rev(lst')
end;
If we try slice'([1,2,3,4,77,8,7], 1, 5) the result is [2, 3, 4, 77, 8].
To get to [2, 4, 8] we just need to drop every second element. This can be defined in terms of simple recursion as follows.
fun dropn(n, lst) =
let
fun dropn'(_, _, []) = []
| dropn'(n, c, x::xs) =
if c = n then x :: dropn'(n, 1, xs)
else dropn'(n, c + 1, xs)
in
dropn'(n, n, lst)
end
But apparently you can't use recursion, so let's use a fold.
fun drop(n, lst) =
List.foldl
(fn (x, (acc, i)) => if i = n then (x :: acc, 1) else (acc, i + 1))
([], n)
lst
Now if we try drop(2, [1,2,3,4,77,8,7]) we get ([7, 77, 3, 1], 1) which does contain the list we want, but also the counter, and the list is backwards because of the way we've built it up. Let's consider how that accumulator works as we step through this simple example.
Initial state:
lst: [1,2,3,4,77,8,7]
acc: []; i: 2
First iteration:
x: 1
acc: [1]; i: 2
Second Iteration:
x: 2
acc: 1 :: []; i: 1
Third iteration:
x: 3
acc: 3 :: 1 :: []; i: 2
Fourth iteration:
x: 4
acc: 3 :: 1 :: []; i: 1
Fifth iteration:
x: 77
acc: 77 :: 3 :: 1 :: []; i: 2
Sixth iteration:
x: 8
acc: 77 :: 3 :: 1 :: []; i: 1
Seventh iteration:
x: 7
acc: 7 :: 77 :: 3 :: 1 :: []; i: 2
Final step:
remaining list: []
acc: 7 :: 77 :: 3 :: 1 :: [] or [7, 77, 3, 1]; i: 1
Easy enough, though, to extract and reverse that list.
fun drop(n, lst) =
let
val (lst', _) = List.foldl
(fn (x, (acc, i)) => if i = n then (x :: acc, 1) else (acc, i + 1))
([], n)
lst
in
List.rev lst'
end
So now drop(2, [1,2,3,4,77,8,7]) evaluates to [1, 3, 77, 7].
Between these two answers, it should be very straightforward to put together a solution to your problem, and hopefully to see why it works.
One solution to correctly skip elements you don't want in your
resulting list, is to add a parameter to your function used to fold
your list. The meaning of this parameter is basically "how much items
you still want to skip".
As an example, below is a solution that uses List.foldl. The
function used to fold items of the list takes two parameters: the
first one is the one discussed above and the second one is the
resulting list being constructed.
fun cutt lst (idx_start, idx_end, interval) = let
val (_, result) =
List.foldl
(fn (x, (0, result)) =>
(* no more item to skip => add x to the resulting list *)
(interval - 1, x :: result)
| (_, (n, result)) =>
(* there are still items to skip *)
(n - 1, result))
(idx_start, []) (* initially we skip idx_start items *)
lst
in
(* items are prepended in the resulting list in reverse order =>
reverse the list *)
List.rev result
end;
val x = cutt [1, 2, 3, 4, 77, 8, 7] (1, 5, 2);
Of course the function needs to be adapted as it does not take care
of the idx_end parameter.
the type is defined as follows:
gap :: (Eq a) => a -> a -> [a] -> Maybe Int
I have been stuck on this problem for more than an hour and have no idea how to approach the problem. I am aware that it requires the use of fold and am familiar with that topic.
Please take into consideration that either foldl or foldr must be used.
The output when called ought to look like this
gap 3 8 [1..10]
=Just 5
gap 8 3 [1..10]
=Nothing
gap 'h' 'l' "hello"
=Just 2
gap 'h' 'z' "hello"
=Nothing
You might dropWhile the list until you find the starting element and then fold from the right, starting with Nothing, replacing that with Just 1 once you hit the end element, and fmaping +1 to the accumulator. In code:
gap :: Eq a => a -> a -> [a] -> Maybe Int
gap from to xs = case dropWhile (/= from) xs of
[] -> Nothing
(_:rest) -> gap' to rest
gap' :: Eq a => a -> [a] -> Maybe Int
gap' to = foldr f Nothing
where f x acc | x == to = Just 1
| otherwise = (+1) <$> acc
The nice thing is that it works correctly if you have several occurences of the elements in your sequence:
*Main> gap 3 8 $ [1..10] ++ [1..10]
Just 5
*Main> gap 3 8 [1, 2, 3, 3, 3, 8]
Just 3
Maybe my solution isn't nice, but it works
import Control.Monad
import Data.Function
import Data.Foldable
(...) = (.) . (.)
gap x y = liftA2 ((guard . (> 0) =<<) ... liftA2 (subtract `on` fst))
(find ((==x) . snd)) (find((==y) . snd)) . zip [0..]
Does some standard Haskell library define a data type like this
data ListWithEnd e a = Cons a (ListWithEnd e a)
| End e
That is a list whose terminating element carries a value of a designated type?
So ListWithEnd () is isomorphic to [] and ListWithEnd Void is isomorphic to infinite streams. Or, viewed differently, ListWithEnd e a is very close to ConduitM () a Identity e..
We can define ListWithEnd as follows:
import Control.Monad.Free
type LWE a e = Free ((,) a) e
We generally have an expectation that abstract or generic representations should reward us with an overall reduction of boilerplate. Let's see what this representation provides us.
In any case, we shall define a pattern synonym for the cons case:
{-# LANGUAGE PatternSynonyms #-}
pattern x :> xs = Free (x, xs)
infixr 5 :>
We can map, fold and traverse over the end element:
fmap (+1) (0 :> Pure 0) == (0 :> Pure 1)
traverse print (0 :> Pure 1) -- prints 1
The Applicative instance gives us very neat concatenation:
xs = 1 :> 2 :> Pure 10
ys = 3 :> 4 :> Pure 20
xs *> ys == 1 :> 2 :> 3 :> 4 :> Pure 20 -- use right end
xs <* ys == 1 :> 2 :> 3 :> 4 :> Pure 10 -- use left end
(+) <$> xs <*> ys == 1 :> 2 :> 3 :> 4 :> Pure 30 -- combine ends
We can map over the list elements, if a bit tortuously:
import Data.Bifunctor -- included in base-4.8!
hoistFree (first (+10)) xs == 11 :> 12 :> Pure 10
And we can make use of iter, of course.
iter (uncurry (+)) (0 <$ xs) == 3 -- sum list elements
It would be nice if LWE could be a Bitraversable (and Bifunctor and Bifoldable), because then we could access the list elements in a more generic and principled way. For this we definitely need a newtype:
newtype LWE a e = LWE (Free ((,) a) e) deriving (lots of things)
instance Bifunctor LWE where bimap = bimapDefault
instance Bifoldable LWE where bifoldMap = bifoldMapDefault
instance Bitraversable LWE where bitraverse = ...
But at this point we might think about just writing the plain ADT out and writing the Applicative, Monad and Bitraversable instances in a couple of lines of code. Alternatively, we could use lens and write a Traversal for the list elements:
import Control.Lens
elems :: Traversal (LWE a e) (LWE b e) a b
elems f (Pure e) = pure (Pure e)
elems f (x :> xs) = (:>) <$> f x <*> elems f xs
Thinking further along this line, we should make a Lens for the end element. This is a bit of a bonus over the generic Free interface, since we know that every finite LWE must contain exactly one end element, and we can make this explicit by having a Lens for it (rather than a Traversal or Prism).
end :: Lens (LWE a e) (LWE a e') e e'
end f (Pure e) = Pure <$> f e
end f (x :> xs) = (x :>) <$> end f xs
I'm trying to learn coding in Haskell.
I started with an easy example "the product of a list".
product :: [Integer] -> Integer
product [] = 1
product (x:xs) = x * product xs
I finished this quickly.
Another way is the product function in the API. (product List -> product)
I wonder if there is another iterative way to solve my problem?
You can use a fold:
product :: Num a => [a] -> a
product xs = foldl (*) 1 xs
This can also be done strictly with foldl' or foldr, the differences mostly are performance, but since you're just starting out I'll skip that lecture this time.
So what does a fold do? Let's start with the basic definition of foldl:
foldl :: (a -> b -> a) -> a -> [b] -> a
foldl f acc [] = acc
foldl f acc (x:xs) = foldl f (f acc x) xs
What this does is takes a function f :: a -> b -> a which takes an accumulator and an additional value, which is fed to it from the list of values. It iteratively applies this function, generating a new accumulator at each step, until it runs out of values in the list. For (*) it looks something like
> foldl (*) 1 [1, 2, 3, 4]
| foldl (*) (1 * 1) [2, 3, 4] = foldl (*) 1 [2, 3, 4]
| foldl (*) (1 * 2) [3, 4] = foldl (*) 2 [3, 4]
| foldl (*) (2 * 3) [4] = foldl (*) 6 [4]
| foldl (*) (6 * 4) [] = foldl (*) 24 []
| 24
I should add that this isn't exactly how it's performed in memory unless you use foldl', which is the strict version, but it's easier to follow this way.
Well in Haskell we don't have loops so iterative is relative, but here's the "functional iteration approach"
product = foldl' (*) 1
folds are the equivalent of loops in imperative languages. foldl' in particular is tail recursive and strict so it will run in constant space, similar to a loop.
If we were to write it explicitly
product = go 1
where go accum (x:xs) = go (accum * x) xs
go accum _ = accum -- Subtle performances
-- differences with strictness
This is still recursive, but will compile to similar assembly.
I'm trying to write a function in SML that takes in a list of ints and will output a list of ordered pairs of ints. The ordered pairs first int is the int that occurred in the input list and the second int in the ordered pair is the number of times it occurred in the input list. Also the list returned should be in ascending order according to the first int in the ordered pairs.
For example input list [1, 1, 1, 2, 3, 3, 5] would output as [(1,3), (2, 1), (3, 2), (5, 1)].
So far I have a function that uses foldl
UPDATED the code since original post.
fun turnIntoPairs l = foldl (fn (e, a) => if List.exists (fn (x, _) => x = e) a then x + 1 else a # [(e, 1)]) [] l;
I'm having trouble updating the list where I find the ordered pair that is already in the list - I want to add one to the second int in the ordered pair that was found while it's still in the list.
Any help would be greatly appreciated!
C:\Program Files (x86)\SMLNJ\\bin\.run\run.x86-win32.exe: Fatal error -- Uncaught exception Error with 0
raised at ../compiler/TopLevel/interact/evalloop.sml:66.19-66.27
[autoloading done]
C:\Users\Localadmin\Desktop\CS 671\Program 3\commonFactors.sml:1.87 Error: unbound variable or constructor: x
C:\Users\Localadmin\Desktop\CS 671\Program 3\commonFactors.sml:1.44-1.110 Error: types of if branches do not agree [literal]
then branch: int
else branch: (''Z * int) list
in expression:
if (List.exists (fn <pat> => <exp>)) a
then <errorvar> + 1
else a # (e,1) :: nil
[Finished in 0.5s with exit code 1]
Not really sure how to fix your current program, but you can solve this problem by splitting it in two: grouping equal elements and then ordering the list.
(* Groups successive equal elements into a tuples (value, count) *)
fun group (l as (x :: _)) =
let val (firstGroup, rest) = List.partition (fn y => x = y) l
in
(x, List.length firstGroup) :: (group rest)
end
| group [] = []
(* Now that we have our elements grouped, what's left is to order
them as required. *)
fun turnIntoPairs xs =
ListMergeSort.sort (fn ((x, _), (y, _)) => x >= y) (group xs)
Let's just look at the function you're passing to foldl:
(fn (e, a) => if List.exists (fn (x, _) => x = e) a then x + 1 else a # [(e, 1)])
The first problem (which the type-checker is complaining about) is that your if expression returns either x + 1, or a # [(e, 1)], which seems problematic on account of the former being a value of type int and the latter being of type (int * int) list.
Let's rewrite your code using some helper functions that I won't define and see if it gets clearer:
(fn (e, a) => if List.exists (fn (x, _) => x = e) a then increment a e else a # [(e, 1)])
Where increment has the type (int * int) list -> int -> (int * int) list.
Can you implement increment?
Like Gian, I would prefer to divide this into two functions: One that folds and one helper function that inserts. Incidentally, the insert function would take an element and an existing (int * int) list just as the accumulator function that fold accepts these two arguments.
Normally I would write an insert function curried (i.e. insert x xs) but if I write it uncurried (i.e. insert (x, xs)), I can pass it directly to foldl:
fun insert (x, []) = [(x,1)]
| insert (x, ((y,c)::xs)) =
if x = y then (y,c+1)::xs else (y,c)::insert (x, xs)
fun turnIntoPairs xs = foldl insert [] xs