SML map a filter? - sml

If I have this code:
fun coord_select (x : int, cs : (int*int) list) =
List.filter (fn (first, _) => first = x ) cs
testing with input gives this:
coord_select (2, [(2,2),(2,3),(3,3),(4,3)])
: val it = [(2,2),(2,3)] : (int * int) list
Now, what if I don't give the desired first coordinate as an int but as a list of several required first coordinates such as [3,4], i.e., I want all coordinate tuples that start with 3 as well as 4? The easy way would simply to create a recursive wrapper around this that went through the list and plugged in the value as coord_select's first variable. But I would like to understand nested things better than such brute force. So I came up with this:
fun coord_match (fs : int list, cs :(int*int) list) =
map (coord_select (f, cs)) fs
but this can't really work because, as was pointed out, coord_select in the map is actually trying to return a list -- and how does map know to plug in the members of fs into f in the first place? Common Lisp does have a device to keep functions like this from running, i.e., the ' operator. But this wouldn't help, again, because map doesn't know which variable fs is supplying. For input, e.g., I have these coordinates:
[(2,2),(2,3),(3,3),(4,3)]
and I have this list of x-coordinates to match against the above list
[3,4]
Again, I could just put a recursive wrapper around this, but I'm reaching for a more elegant nested solution from the greater fold family.

what if I don't give the desired first coordinate as an int but as a list of several required first coordinates such as [3,4], i.e., I want all coordinate tuples that start with 3 and 4
It sounds like you want all coordinate tuples that start with 3 or 4, since a coordinate can't both be 3 and 4.
Given that, you can write coord_select like:
fun member (x, xs) =
List.exists (fn x2 => x = x2) xs
fun coord_select (xs, coords) =
List.filter (fn (x, _) => member (x, xs)) coords
the greater fold family
This family is called catamorphisms, of which map, filter, exists and foldl belong. Since foldl is the most general of these, it is technically possible to write the code above using folds entirely:
fun coord_select (xs, coords) =
foldr (fn ((x, y), acc1) =>
if foldl (fn (x2, acc2) => acc2 orelse x = x2) false xs
then (x, y) :: acc1
else acc1) [] coords
but as should be evident, explicit folds are not very readable.
If there's a specialised combinator that does a job, you would rather want that over a fold. And if it doesn't exist, creating it from slightly less specialised combinators improves readability. Folding is as close to manual recursion as you get and so provides little information to the reader about what kind of recursion we're attempting.
For that reason I also made member from exists, since exists requires me to specify a predicate and my predicate is "equality with x"; so even exists, I feel, adds clutter to the coord_select function.
You can learn more about list catamorphisms in functional programming by reading Functional Programming with Bananas, Lenses, Envelopes and Barbed Wire (1991) by Meijer, Fokkinga, Paterson.

Related

How do I combine consectuive numbers in a list into a range in Haskell?

I'm trying to grapple my head around Haskell and I'm having a hard time pinning down the general procedure/algorithm for this specific task. What I want to do is basically give Haskell a list [1,2,3,5,6,9,16,17,18,19] and have it give me back [1-3, 5, 6, 9, 16-19] so essentially turning three or more consecutive numbers into a range in the style of lowestnumber - highestnumber. What I have issue with it I suppose is the all too common difficulty grappling with with the functional paradigm of Haskell. So I would really appreciate a general algorithm or an insight into how to view this from an "Haskellian" point of view.
Thanks in advance.
If I understand the question correctly, the idea is to break up the input lists in chunks, where a chunk is either a single input element or a range of at least three consecutive elements.
So, let's start by defining a datatype for representing such chunks:
data Chunk a = Single a | Range a a
As you can see, the type is parametric in the type of input elements.
Next, we define a function chunks to actually construct a list of chunks from a list of input elements. For this, we require the ability to compare input elements and to obtain the immediate consecutive for a given input element (that is, its successor). Hence, the type of the function reads
chunks :: (Eq a, Enum a) => [a] -> [Chunk a]
Implementation is relatively straightforward:
chunks = foldr go []
where
go x (Single y : Single z : cs) | y == succ x && z == succ y = Range x z : cs
go x (Range y z : cs) | y == succ x = Range x z : cs
go x cs = Single x : cs
We traverse the list from right to left, generating chunks as we go. We generate a range if an input element precedes its two immediate consecutive elements (the first case of the helper function go) or if it precedes a range that starts with its immediate consecutive (the second case). Otherwise, we generate a single element (the final case).
To arrange for pretty output, we declare applications of the type constructor Chunk to be instances of the class Show (given that the type of input elements is in Show):
instance Show a => Show (Chunk a) where
show (Single x ) = show x
show (Range x y) = show x ++ "-" ++ show y
Returning to the example from the question, we then have:
> chunks [1,2,3,5,6,9,16,17,18,19]
[1-3,5,6,9,16-19]
Unfortunately, things are slightly more complicated if we need to account for bounded element types; such types have a largest element for which succ is undefined:
> chunks [maxBound, 1, 2, 3] :: [Chunk Int]
*** Exception: Prelude.Enum.succ{Int}: tried to take `succ' of maxBound
This suggests that we should abstract from the specific approach for determining whether one elements succeeds another:
chunksBy :: (a -> a -> Bool) -> [a] -> [Chunk a]
chunksBy succeeds = foldr go []
where
go x (Single y : Single z : cs) | y `succeeds` x && z `succeeds` y =
Range x z : cs
go x (Range y z : cs) | y `succeeds` x = Range x z : cs
go x cs = Single x : cs
Now, the version of chunks that was given above, can be expressed in terms of chunksBy simply by writing
chunks :: (Eq a, Enum a) => [a] -> [Chunk a]
chunks = chunksBy (\y x -> y == succ x)
Moreover, we can now also implement a version for bounded input types as well:
chunks' :: (Eq a, Enum a, Bounded a) => [a] -> [Chunk a]
chunks' = chunksBy (\y x -> x /= maxBound && y == succ x)
That merrily gives us:
> chunks' [maxBound, 1, 2, 3] :: [Chunk Int]
[9223372036854775807,1-3]
First, all elements of a list must be of the same type. Your resulting list has two different types. Ranges (for what ever that means) and Ints. We should convert one single digit into a range with lowest and highest been the same.
Been said so, You should define the Range data type and fold your list of Int into a list of Range
data Range = Range {from :: Int , to :: Int}
intsToRange :: [Int] -> [Range]
intsToRange [] = []
intsToRange [x] = [Range x x]
intsToRange (x:y:xs) = ... -- hint: you can use and auxiliar acc which holds the lowest value and keep recursion till find a y - x differece greater than 1.
You can also use fold, etc... to get a very haskelly point of view
Use recursion. Recursion is a leap of faith. It is imagining you've already written your definition and so can ("recursively") call it on a sub-problem of your full problem, and combine the (recursively calculated) sub-result with the left-over part to get the full solution -- easy:
ranges xs = let (leftovers, subproblem) = split xs
subresult = ranges subproblem
result = combine leftovers subresult
in
result
where
split xs = ....
combine as rs = ....
Now, we know the type of rs in combine (i.e. subresult in ranges) -- it is what ranges returns:
ranges :: [a] -> rngs
So, how do we split our input list xs? The type-oriented design philosophy says, follow the type.
xs is a list [a] of as. This type has two cases: [] or x:ys with x :: a and ys :: [a]. So the easiest way to split a list into a smaller list and some leftover part is
split (x:xs) = (x, ys)
split [] = *error* "no way to do this" -- intentionally invalid code
Taking note of the last case, we'll have to tweak the overall design to take that into account. But first things first, what's the rngs type could be? Going by your example data, it's a list of rngs, naturally, rngs ~ [rng].
A rng type though, we have a considerable degree of freedom to make it to be whatever we want. The cases we have to account for are pairs and singletons:
data Rng a = Single a
| Pair a a
.... and now we need to fit the jagged pieces together into one picture.
Combining a number with a range which starts from consecutive number is obvious.
Combining a number with a single number will have two obvious cases, for whether those numbers are consecutive or not.
I think / hope you can proceed from here.

Calculate the differences of list elements using zipWith

I have to make a function called differences, where I calculate the difference of every pair with zipWith and put it in a list.
For example differences [1..5] == [1, 1, 1, 1].
So [2-1, 3-2, 4-3, 5-4] == [1, 1, 1, 1].
I thought of making list of tuples, like this:
[1..5] = [(1,2), (2,3), (3,4), (4,5)]
Then use list comprehesion like this:
[zipWith (-) a b | a <- y, b <- x]
where x is the first element of the tuple and y is the second.
The functions type is differences :: Num a => [a] -> [a].
You're nearly there - but zipWith itself returns a list, so you don't want to put that inside a list comprehension unless you want the result to be a list of lists (which you don't, here).
zipWith (-) is absolutely the right idea here - it takes 2 lists and gives a new list given by taking the difference between corresponding elements of the given lists. Your output list, in your case, is intended to be 1 element shorter than the one input list, and you want to use zipWith (-) on 2 lists which consist of:
all elements of the given list, other than the first
all elements of the given list, other than the last
Haskell already gives us convenient functions for these, namely tail and init.
So the function you're looking for is:
differences xs = zipWith (-) (tail xs) (init xs)
Note that this isn't ideal, because both init and tail will crash your program with an ugly runtime error if xs is empty. It makes sense to output an empty list if you present an empty list to this function (although you could argue it doesn't, since you will get an empty list from a singleton list), so you can avoid a runtime crash by defining the function via pattern matching to explicitly cater for the empty list:
differences [] = []
differences xs = zipWith (-) (tail xs) (init xs)
While personally I think this is fine, and very explicit, you don't actually need to use both init and tail - zipWith works just fine if presented with lists of unequal length, when it will simply trim the larger one down to size. So differences xs = zipWith (-) (tail xs) xs is a viable, and slightly terser, alternative.
Building off Robin Zigmond's answer, the Applicative instance for functions works well here:
(f <*> g) xs == f xs (g xs)
so
differences = zipWith subtract <*> tail
(where subtract = flip (-).)
As 4castle suggests, using drop 1 instead of tail in Robin Zigmond's second, init-less solution means we can omit the [] case, as drop 1 [] = [] (unlike tail [], which leads to a runtime error):
differences xs = zipWith (-) (drop 1 xs) xs
To contrast with this solution with no explicit pattern deconstruction, I will mention a spelling using none of init, tail and drop:
differences xs#(_:ys) = zipWith (-) ys xs

How to compare each element separately of two char lists Standard ML

I am very new to SML and i am trying to write a function where it compares two char lists, in a way that it takes one character from list1 and compares it with all the characters from list2, for example
val list1 = explode("abcdefghijklmnopqrstuvwxyz")
val list2 = explode("bcdaghklfeijonmtrqpsvuwyzx!-232=,./;'[]{}:?<")
so from list1 it takes the element 'a', and then compares it with each element of list2 and it keeps checking all elements, if the jumbled list2 is equal to to the non jumbled list1 then it returns true
This sounds like an XY problem,
The XY problem is asking about your attempted solution rather than your actual problem. This leads to enormous amounts of wasted time and energy, both on the part of people asking for help, and on the part of those providing help.
Are you testing if list1 is a subset, sub-multiset, sub-string, sub-sequence, or a permutation of list2? Or if they are set-equivalent? Try and express your actual problem and then describe your attempted solution. :-)
You probably want to use a combination of List.exists and List.all.
For example, if you were to test if list1 is a subset of list2:
fun contains (ys, x) = List.exists (fn y => x = y) ys
fun isSubsetOf (xs, ys) = List.all (fn x => contains (ys, x)) xs
Which says: For all x ∈ xs, there must exist a y ∈ ys such that x = y.

elm list comprehensions, retrieving the nth element of a list

I was trying to do a simulation of the Rubik's cube in Elm when I noticed Elm doesn't support list comprehensions. In Haskell or even Python I would write something like:
ghci> [2*c | c <- [1,2,3,4]]
[2,4,6,8]
I could not find a way in Elm. The actual list comprehension I had to write was (in Haskell):
ghci> let x = [0,1,3,2]
ghci> let y = [2,3,1,0]
ghci> [y !! fromIntegral c | c <- x]
[2,3,0,1]
where fromIntegral :: (Integral a, Num b) => a -> b turns Integer into Num.
In Elm, I tried to use Arrays:
x = Array.fromList [0,1,3,2]
y = Array.fromList [2,3,1,0]
Array.get (Array.get 2 x) y
And I started getting difficulties with Maybe types:
Expected Type: Maybe number
Actual Type: Int
In fact, I had to look up what they were. Instead of working around the maybe, I just did something with lists:
x = [0,1,3,2]
y = [2,3,1,0]
f n = head ( drop n x)
map f y
I have no idea if that's efficient or correct, but it worked in the cases I tried.
I guess my two main questions are:
does Elm support list comprehensions? ( I guess just use map)
how to get around the maybe types in the Array example?
is it efficient to call head ( drop n x) to get the nth element of a list?
Elm doesn't and will not support list comprehensions: https://github.com/elm-lang/Elm/issues/147
The style guide Evan refers to says 'prefer map, filter, and fold', so.. using `map:
map ((y !!).fromIntegral) x
or
map (\i-> y !! fromIntegral i) x
Commenters point out that (!!) isn't valid Elm (it is valid Haskell). We can define it as either:
(!!) a n = head (drop n a), a total function.
or perhaps
(!!) a n = case (head (drop n a)) of
Just x -> x
Nothing -> crash "(!!) index error"
I don't know much about Elm, so I can't answer to whether it supports list comprehensions (couldn't find anything via Google about it either way), but I can answer your other two questions.
How to get around the Maybe types in the Array example?
The type of Array.get is Int -> Array a -> Maybe a, which means that it returns either Nothing or Just x, where x is the value at the given index. If you want to feed the result of one of these operations into another, in Haskell you could just do
Array.get 2 x >>= \i -> Array.get i y
Or with do notation:
do
i <- Array.get 2 x
Array.get i y
However, from a quick search it seems that Elm may or may not support all monadic types, but hopefully you can still use a case statement to get around this (it's just not very fun)
case Array.get 2 x of
Nothing -> Nothing
Just i -> Array.get i y
In fact, I would recommend writing a function to do this in general for you, it's just a direct clone of >>= for Maybe in Haskell:
mayBind :: Maybe a -> (a -> Maybe b) -> Maybe b
mayBind Nothing _ = Nothing
mayBind (Just x) f = f x
Then you could use it as
Array.get 2 x `mayBind` (\i -> Array.get i y)
Is it efficient to call head (drop n x) to get the nth element of a list?
No, but neither is direct indexing, which is equivalent to head . drop n. For lists, indexing will always be O(n) complexity, meaning it takes n steps to get the nth element from the list. Arrays have a different structure, which lets them index in logarithmic time, which is significantly faster. For small lists (< 100 elements), this doesn't really matter, but once you start getting more than a hundred or a thousand elements, it starts becoming a bottleneck. Lists are great for simple code that doesn't have to be the fastest, as they are generally more convenient. Now, I don't know how exactly this gets translated in Elm, it may be that Elm will convert them into Javascript arrays, which are true arrays and indexable in O(1) time. If Elm uses its own version of Haskell lists after it's been compiled, then you'll still have a slowdown.

Using Haskell's map function to calculate the sum of a list

Haskell
addm::[Int]->Int
addm (x:xs) = sum(x:xs)
I was able to achieve to get a sum of a list using sum function but is it possible to get the sum of a list using map function? Also what the use of map function?
You can't really use map to sum up a list, because map treats each list element independently from the others. You can use map for example to increment each value in a list like in
map (+1) [1,2,3,4] -- gives [2,3,4,5]
Another way to implement your addm would be to use foldl:
addm' = foldl (+) 0
Here it is, the supposedly impossible definition of sum in terms of map:
sum' xs = let { ys = 0 : map (\(a,b) -> a + b) (zip xs ys) } in last ys
this actually shows how scanl can be implemented in terms of map (and zip and last), the above being equivalent to foldl (+) 0 xs === last $ scanl (+) 0 xs:
scanl' f z xs = let { ys = z : map (uncurry f) (zip ys xs) } in ys
I expect one can calculate many things with map, arranging for all kinds of information flow through zip.
edit: the above is just a zipWith in disguise of course (and zipWith is kind of a map2):
sum' xs = let { ys = 0 : zipWith (+) ys xs } in last ys
This seems to suggest that scanl is more versatile than foldl.
It is not possible to use map to reduce a list to its sum. That recursive pattern is a fold.
sum :: [Int] -> Int
sum = foldr (+) 0
As an aside, note that you can define map as a fold as well:
map :: (a -> b) -> ([a] -> [b])
map f = fold (\x xs -> f x : xs) []
This is because foldr is the canonical recursive function on lists.
References: A tutorial on the universality and expressiveness of fold, Graham Hutton, J. Functional Programming 9 (4): 355–372, July 1999.
After some insights I have to add another answer: You can't get the sum of a list with map, but you can get the sum with its monadic version mapM. All you need to do is to use a Writer monad (see LYAHFGG) over the Sum monoid (see LYAHFGG).
I wrote a specialized version, which is probably easier to understand:
data Adder a = Adder a Int
instance Monad Adder where
return x = Adder x 0
(Adder x s) >>= f = let Adder x' s' = f x
in Adder x' (s + s')
toAdder x = Adder x x
sum' xs = let Adder _ s = mapM toAdder xs in s
main = print $ sum' [1..100]
--5050
Adder is just a wrapper around some type which also keeps a "running sum." We can make Adder a monad, and here it does some work: When the operation >>= (a.k.a. "bind") is executed, it returns the new result and the value of the running sum of that result plus the original running sum. The toAdder function takes an Int and creates an Adder that holds that argument both as wrapped value and as running sum (actually we're not interested in the value, but only in the sum part). Then in sum' mapM can do its magic: While it works similar to map for the values embedded in the monad, it executes "monadic" functions like toAdder, and chains these calls (it uses sequence to do this). At this point, we get through the "backdoor" of our monad the interaction between list elements that the standard map is missing.
Map "maps" each element of your list to an element in your output:
let f(x) = x*x
map f [1,2,3]
This will return a list of the squares.
To sum all elements in a list, use fold:
foldl (+) 0 [1,2,3]
+ is the function you want to apply, and 0 is the initial value (0 for sum, 1 for product etc)
As the other answers point out, the "normal" way is to use one of the fold functions. However it is possible to write something pretty similar to a while loop in imperative languages:
sum' [] = 0
sum' xs = head $ until single loop xs where
single [_] = True
single _ = False
loop (x1 : x2 : xs) = (x1 + x2) : xs
It adds the first two elements of the list together until it ends up with a one-element list, and returns that value (using head).
I realize this question has been answered, but I wanted to add this thought...
listLen2 :: [a] -> Int
listLen2 = sum . map (const 1)
I believe it returns the constant 1 for each item in the list, and returns the sum!
Might not be the best coding practice, but it was an example my professor gave to us students that seems to relate to this question well.
map can never be the primary tool for summing the elements of a container, in much the same way that a screwdriver can never be the primary tool for watching a movie. But you can use a screwdriver to fix a movie projector. If you really want, you can write
import Data.Monoid
import Data.Foldable
mySum :: (Foldable f, Functor f, Num a)
=> f a -> a
mySum = getSum . fold . fmap Sum
Of course, this is silly. You can get a more general, and possibly more efficient, version:
mySum' :: (Foldable f, Num a) => f a -> a
mySum' = getSum . foldMap Sum
Or better, just use sum, because its actually made for the job.