In F# is there a way to map for example [2;2;2;2;5;5;5;7;7] to [4,3,2] without recursion and without mutable? I looked through the Array and List members and found Reduce but that does not seem to help.
You can implement it quickly using Seq.countBy. Using F# interactive, it looks like this:
> [2;2;2;2;5;5;5;7;7] |> Seq.countBy id;;
val it : seq<int * int> = seq [(2, 4); (5, 3); (7, 2)]
If you only want the counts (and not the values which were repeated), you can just pipe the result into Seq.map:
> [2;2;2;2;5;5;5;7;7] |> Seq.countBy id |> Seq.map snd;;
val it : seq<int> = seq [4; 3; 2]
Note that you can implement this using Seq.groupBy, but Seq.countBy is much more efficient: Seq.groupBy consumes more memory because it has to store all of the groups, whereas Seq.countBy stores just one int (the counter) for each key in the sequence.
Try this:
[2;2;2;2;5;5;5;7;7] |> Seq.groupBy id |> Seq.map (snd >> Seq.length)
Seq.groupBy id collects the list up into groups of equal elements - using the identity function id means that the elements of the sequence are used directly as the "keys" for the equality check. This gives us a sequence of the original elements paired up with the repeats:
seq [(2, seq [2; 2; 2; 2]); (5, seq [5; 5; 5]); (7, seq [7; 7])]
Then for each of the inner sequences, we use snd to just get the sequence of repeats, and Seq.length to get its length. >> is the composition operator that applies the first function and then the second.
Related
I have the following question "Given a list of integer pairs, write a function to return a list of even numbers in that list in sml".
this is what I've achieved so far
val x = [(6, 2), (3, 4), (5, 6), (7, 8), (9, 10)];
fun isEven(num : int) =
if num mod 2 = 0 then num else 0;
fun evenNumbers(list : (int * int) list) =
if null list then [] else
if isEven(#1 (hd list)) <> 0
then if isEven(#2 (hd list)) <> 0
then #1 (hd list) :: #1 (hd list) :: evenNumbers(tl list)
else []
else if isEven(#2 (hd list)) <> 0
then #1 (hd list) :: evenNumbers(tl list)
else [];
evenNumbers(x);
the result should be like this [6,2,4,6,8,10]
any help would be appreciated.
I see two obvious problems.
If both the first and second number are even, you do
#1 (hd list) :: #1 (hd list) :: evenNumbers(tl list)
which adds the first number twice and ignores the second.
If the first number is odd and the second even, you do
#1 (hd list) :: evenNumbers(tl list)
which adds the number that you know is odd and ignores the one you know is even.
Programming with selectors and conditionals gets complicated very quickly (as you've noticed).
With pattern matching, you could write
fun evenNumbers [] = []
| evenNumber ((x,y)::xys) = ...
and reduce the risk of using the wrong selector.
However, this still makes for complicated logic, and there is a better way.
Consider the simpler problem of filtering the odd numbers out of a list of numbers, not pairs.
If you transform the input into such a list, you only need to solve that simpler problem (and there's a fair chance that you've already solved something very similar in a previous exercise).
Exercise: implement this transformation. Its type will be ('a * 'a) list -> 'a list.
Also, your isEven is more useful if it produces a truth value (if you ask someone, "is 36 even?", "36" is a very strange answer).
fun isEven x = x mod 2 = 0
Now, evenNumbers can be implemented as "just" a combination of other, more general, functions.
So running your current code,
- evenNumbers [(6, 2), (3, 4), (5, 6), (7, 8), (9, 10)];
val it = [6,6,3,5,7,9] : int list
suggests that you're not catching all even numbers, and that you're catching some odd numbers.
The function isEven sounds very much like you want to have the type int -> bool like so:
fun isEven n =
n mod 2 = 0
Instead of addressing the logic error of your current solution, I would like to propose a syntactically much simpler approach which is to use pattern matching and fewer explicit type annotations. One basis for such a solution could look like:
fun evenNumbers [] = ...
| evenNumbers ((x,y)::pairs) = ...
Using pattern matching is an alternative to if-then-else: the [] pattern is equivalent to if null list ... and the (x,y)::pairs pattern matches when the input list is non-empty (holds at least one element, being (x,y). At the same time, it deconstructs this one element into its parts, x and y. So in the second function body you can express isEven x and isEven y.
As there is a total of four combinations of whether x and y are even or not, this could easily end up with a similarly complicated nest of if-then-else's. For this I might do either one of two things:
Use case-of (and call evenNumbers recursively on pairs):
fun evenNumbers [] = ...
| evenNumbers ((x,y)::pairs) =
case (isEven x, isEven y) of
... => ...
| ... => ...
Flatten the list of pairs into a list of integers and filter it:
fun flatten [] = ...
| flatten ((x,y)::pairs) = ...
val evenNumbers pairs = ...
I came away from Professor Frisby's Mostly Adequate Guide to Functional Programming with what seems to be a misconception about Maybe.
I believe:
map(add1, Just [1, 2, 3])
// => Just [2, 3, 4]
My feeling coming away from the aforementioned guide is that Maybe.map should try to call Array.map on the array, essentially returning Just(map(add1, [1, 2, 3]).
When I tried this using Sanctuary's Maybe type, and more recently Elm's Maybe type, I was disappointed to discover that neither of them support this (or, perhaps, I don't understand how they support this).
In Sanctuary,
> S.map(S.add(1), S.Just([1, 2, 3]))
! Invalid value
add :: FiniteNumber -> FiniteNumber -> FiniteNumber
^^^^^^^^^^^^
1
1) [1, 2, 3] :: Array Number, Array FiniteNumber, Array NonZeroFiniteNumber, Array Integer, Array ValidNumber
The value at position 1 is not a member of ‘FiniteNumber’.
In Elm,
> Maybe.map sqrt (Just [1, 2, 3])
-- TYPE MISMATCH --------------------------------------------- repl-temp-000.elm
The 2nd argument to function `map` is causing a mismatch.
4| Maybe.map sqrt (Just [1, 2, 3])
^^^^^^^^^^^^^^
Function `map` is expecting the 2nd argument to be:
Maybe Float
But it is:
Maybe (List number)
Similarly, I feel like I should be able to treat a Just(Just(1)) as a Just(1). On the other hand, my intuition about [[1]] is completely the opposite. Clearly, map(add1, [[1]]) should return [NaN] and not [[2]] or any other thing.
In Elm I was able to do the following:
> Maybe.map (List.map (add 1)) (Just [1, 2, 3])
Just [2,3,4] : Maybe.Maybe (List number)
Which is what I want to do, but not how I want to do it.
How should one map over Maybe List?
You have two functors to deal with: Maybe and List. What you're looking for is some way to combine them. You can simplify the Elm example you've posted by function composition:
> (Maybe.map << List.map) add1 (Just [1, 2, 3])
Just [2,3,4] : Maybe.Maybe (List number)
This is really just a short-hand of the example you posted which you said was not how you wanted to do it.
Sanctuary has a compose function, so the above would be represented as:
> S.compose(S.map, S.map)(S.add(1))(S.Just([1, 2, 3]))
Just([2, 3, 4])
Similarly, I feel like I should be able to treat a Just(Just(1)) as a Just(1)
This can be done using the join from the elm-community/maybe-extra package.
join (Just (Just 1)) == Just 1
join (Just Nothing) == Nothing
join Nothing == Nothing
Sanctuary has a join function as well, so you can do the following:
S.join(S.Just(S.Just(1))) == Just(1)
S.join(S.Just(S.Nothing)) == Nothing
S.join(S.Nothing) == Nothing
As Chad mentioned, you want to transform values nested within two functors.
Let's start by mapping over each individually to get comfortable:
> S.map(S.toUpper, ['foo', 'bar', 'baz'])
['FOO', 'BAR', 'BAZ']
> S.map(Math.sqrt, S.Just(64))
Just(8)
Let's consider the general type of map:
map :: Functor f => (a -> b) -> f a -> f b
Now, let's specialize this type for the two uses above:
map :: (String -> String) -> Array String -> Array String
map :: (Number -> Number) -> Maybe Number -> Maybe Number
So far so good. But in your case we want to map over a value of type Maybe (Array Number). We need a function with this type:
:: Maybe (Array Number) -> Maybe (Array Number)
If we map over S.Just([1, 2, 3]) we'll need to provide a function which takes [1, 2, 3]—the inner value—as an argument. So the function we provide to S.map must be a function of type Array (Number) -> Array (Number). S.map(S.add(1)) is such a function. Bringing this all together we arrive at:
> S.map(S.map(S.add(1)), S.Just([1, 2, 3]))
Just([2, 3, 4])
How would I flatten a list of lists of integers into a single list of integers in ocaml? The function would work as shown below.
[[1;2];[3;4;5];[];[6]] -> [1;2;3;4;5;6]
As this is homework, it must be done using only fold_left or fold_right, and cannot use the '#' operator, and cannot use recursion. I get that the accumulator is going to be the members of the new list, but I have no clue how to actually move the elements of the original list to the accumulator. Any hints would be appreciated.
Here are some hints:
a. Moving a value to the accumulator is not difficult. If your value is x and your accumulator is a, you can just write x :: a.
b. You mostly need to process all the inner values in a consistent order. That's what folds are for.
c. A fold is for processing the elements of a list. But you have a list of lists.
List.fold_left (fun liRes la ->
List.fold_right ( fun iRes la ->
iRes::la
) liRes la
) [] [[1;2];[3;4;5];[];[6]]
result :
- : int list = [1; 2; 3; 4; 5; 6]
other form :
let (#) =
List.fold_right ( fun iRes la ->
iRes::la
);;
List.fold_left (fun liRes la ->
liRes # la
) [] [[1;2];[3;4;5];[];[6]];;
You can try :
# []#[1;2];;
- : int list = [1; 2]
# (#) [1;2] [3;4];;
- : int list = [1; 2; 3; 4]
Given a sequence of items as follows:
[ ("a", 1); ("a", 2); ("a", 3); ("b", 1); ("c", 2); ("c", 3) ]
How can I convert this lazily into:
{ ("a", { 1; 2; 3}); ("b", { 1 }); ("c", { 2; 3}) }
You can assume that the input data source is already sorted on the grouping key element e.g. "a" "b" and "c".
I'm using the { } there to indicate that it's a lazily-evaluated sequence of items.
I've gotten it working imperatively with two while loops operating over the IEnumerator of the source sequence, but this involves creating reference variables and mutation etc. etc. I'm sure that there are better ways of doing this, perhaps with Recursion or using some of the operations in the Seq library e.g. scan or unfold?
If you want to implement this over IEnumerable<'T> (to make it lazy), then it is necessarily going to be somewhat imperative, because the IEnumerator<'T> type that is used to iterate over the input is imperative. But the rest can be written as a recursive function using sequence expressions.
The following is lazy in the first level (it produces each group lazily), but it does not produce elements of the group lazily (I think that would have pretty subtle semantics):
/// Group adjacent elements of 'input' according to the
/// keys produced by the key selector function 'f'
let groupAdjacent f (input:seq<_>) = seq {
use en = input.GetEnumerator()
// Iterate over elements and keep the key of the current group
// together with all the elements belonging to the group so far
let rec loop key acc = seq {
if en.MoveNext() then
let nkey = f en.Current
if nkey = key then
// If the key matches, append to the group so far
yield! loop key (en.Current::acc)
else
// Otherwise, produce the group collected so far & start a new one
yield List.rev acc
yield! loop nkey [en.Current]
else
// At the end of the sequence, produce the last group
yield List.rev acc
}
// Start with the first key & first value as the accumulator
if en.MoveNext() then
yield! loop (f en.Current) [en.Current] }
Unfortunately, this (pretty useful!) function is not included in the standard F# library, so if you want to group adjacent elements (rather than arbitrary elements in the list using Seq.groupBy), you have to define it yourself...
let p = [("a", 1); ("a", 2); ("a", 3); ("b", 1); ("c", 2); ("c", 3)]
let l = p |> Seq.groupBy fst |> Seq.map(fun x -> fst x, snd x |> Seq.map snd)
In F#+ there is a generic function chunkBy that can be used to do that:
#r "FSharpPlus.dll"
open FSharpPlus
seq [ ("a", 1); ("a", 2); ("a", 3); ("b", 1); ("c", 2); ("c", 3) ]
|> chunkBy fst
|> map (fun (x,y) -> x, map snd y)
And it works with seq, array and list.
The implementation for seq is pretty much the same as the groupdAdjacent from Tomas.
Seq.groupBy fst
Will do the trick
I know how to do the equivalent of Scheme's (or Python's) map and filter functions with the list monad using only the "bind" operation.
Here's some Scala to illustrate:
scala> // map
scala> List(1,2,3,4,5,6).flatMap {x => List(x * x)}
res20: List[Int] = List(1, 4, 9, 16, 25, 36)
scala> // filter
scala> List(1,2,3,4,5,6).flatMap {x => if (x % 2 == 0) List() else List(x)}
res21: List[Int] = List(1, 3, 5)
and the same thing in Haskell:
Prelude> -- map
Prelude> [1, 2, 3, 4, 5, 6] >>= (\x -> [x * x])
[1,4,9,16,25,36]
Prelude> -- filter
Prelude> [1, 2, 3, 4, 5, 6] >>= (\x -> if (mod x 2 == 0) then [] else [x])
[1,3,5]
Scheme and Python also have a reduce function that's often grouped with map and filter. The reduce function combines the first two elements of a list using the supplied binary function, and then combines that result the the next element, and then so on. A common use to to compute the sum or product of a list of values. Here's some Python to illustrate:
>>> reduce(lambda x, y: x + y, [1,2,3,4,5,6])
21
>>> (((((1+2)+3)+4)+5)+6)
21
Is there any way to do the equivalent of this reduce using just the bind operation on a list monad? If bind can't do this on its own, what's the most "monadic" way to perform this operation?
If possible, please limit/avoid the use of syntactic sugar (ie: do notation in Haskell or sequence comprehensions in Scala) when answering.
One of the defining properties of the bind operation is that the result is still "inside" the monad¹. So when you perform bind on a list, the result will again be a list. Since the reduce operation² often results in something other than a list, it can't be expressed in terms of the bind operation.
In addition to that the bind operation on lists (i.e. concatMap/flatMap) only looks at one element at a time and offers no way of reusing the result of previous steps. So even if we're okay with getting the result wrapped in a single-element list, there's no way to do it just with monad operations.
¹ So if you have a type that allows you to perform no operations on it except the ones defined by the monad type class, you can never "break out" of the monad. That's what makes the IO monad works.
² Which is called fold in Haskell and Scala by the way.
If bind can't do this on its own, what's the most "monadic" way to perform this operation?
While the answer given by #sepp2k is correct, there is a way to do a reduce-like operation on a list monadically, but using the product or "writer" monad and an operation which corresponds to distributing the product monad over the list functor.
The definition is:
import Control.Monad.Writer.Lazy
import Data.Monoid
reduce :: Monoid a => [a] -> a
reduce xs = snd . runWriter . sequence $ map tell xs
Let me unpack:
The Writer monad has a data type Writer w a which is basically a tuple (product) of a value a and "written" value w. The type of written values w must be a monoid where the bind operation of the Writer monad is defined something like:
(w, a) >>= f = let (w', b) = f a in (mappend w w', b)
i.e. take the incoming written value, and the result written value, and combine them using the binary operation of the monoid.
The tell operation writes a value, tell :: w -> Writer w (). Thus map tell has type [a] -> [Writer a ()] i.e. a list of monadic values where each element of the original list has been "written" in the monad.
sequence :: Monad m => [m a] -> m [a] corresponds to a distributive law between lists and monads i.e. distribute the monad type over the list type; sequence can be defined in terms of bind as:
sequence [] = return []
sequnece (x:xs) = x >>= (\x' -> (sequence xs) >>= (\xs' -> return $ x':xs'))
(actually the implementation in Prelude uses foldr, a clue to the reduction-like usage)
Thus, sequence $ map tell xs has type Writer a [()]
The runWriter operation unpacks the Writer type, runWriter :: Writer w a -> (a, w),
which is composed here with snd to project out the accumulated value.
An example usage on lists of Ints would be to use the monoid instance:
instance Monoid Int where
mappend = (+)
mempty = 0
then:
> reduce ([1,2,3,4]::[Int])
10