I was having a look at some list operations and came across !!:
(!!) :: [a] -> Int -> a
xs !! n
| n < 0 = negIndex
| otherwise = foldr (\x r k -> case k of
0 -> x
_ -> r (k-1)) tooLarge xs n
The function (\x r k -> ...) has type a -> (Int -> a) -> Int -> a, but foldr takes a function that should only accept two arguments:
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr k z = go
where
go [] = z
go (y:ys) = y `k` go ys
Can someone explain to me why foldr accepts a function that takes 3 arguments with the following type a -> (Int -> a) -> Int -> a? Especially since the result should have the same type as the second argument?
-> is right-associative. So a -> b -> c is a -> (b -> c). Therefore, your type
a -> (Int -> a) -> Int -> a
is the same as
a -> (Int -> a) -> (Int -> a)
and we can see that it fits foldr's type quite well.
(more explanation for others ;)
(!!) :: [a] -> Int -> a
xs !! n
| n < 0 = negIndex
| otherwise = foldr (\x r k -> case k of
0 -> x
_ -> r (k-1)) tooLarge xs n
foldr :: (a -> b -> b) -> b -> [a] -> b
-- ^1 ^2
foldr commonly makes an accumulated(?) value. In this case, foldr makes an
accumulated function (b) of the type (Int -> a)! foldr ... tooLarge xs is evaluated to an
accumulated function, and this accumulated function (^2) takes an argument n. ^1 is a tooLarge function. Interestingly, the buildup of this
accumulated function depends on the value of a free variable n (i.e., k).
For example, ['a', 'b', 'c'] !! 2 is evaluated like below:
\x r k = \'a' r 2 -> r (2-1) (r is not known yet, and drives further evaluations.)
\x r k = \'b' r 1 -> r (1-1)
\x r k = \'c' r 0 -> 'c'
['a', 'b', 'c'] !! 3 goes like this:
\x r k = \'a' r 3 -> r (3-1)
\x r k = \'b' r 2 -> r (2-1)
\x r k = \'c' r 1 -> r (1-1) (r turns out to be tooLarge.) = tooLarge (1-1) (ERROR!)
You can check debug traces:
module Main where
import Debug.Trace
tooLarge _ = errorWithoutStackTrace "!!!: index too large"
negIndex = errorWithoutStackTrace "!!!: negative index"
(!!!) :: Show a => [a] -> Int -> a
xs !!! n
| n < 0 = negIndex
| otherwise = foldr (\x r k -> trace ("x: " ++ show x ++ ", k: " ++ show k) $
case k of
0 -> x
_ -> r (k-1)) tooLarge xs n
main = do
print $ ['a', 'b', 'c'] !!! 2
print $ ['a', 'b', 'c'] !!! 3
-- x: 'a', k: 2
-- x: 'b', k: 1
-- x: 'c', k: 0
-- 'c'
-- x: 'a', k: 3
-- x: 'b', k: 2
-- x: 'c', k: 1
-- sample: !!!: index too large
This (!!) implementation is a report version. The report version of the prelude is more efficient than a familiar naive recursive implementation,
due to optimizations of foldr.
Related
I have the following two type signatures in Haskell:
foo :: (a -> (a,b)) -> a -> [b]
bar :: (a -> b) -> (a -> b -> c) -> a -> c
I want to write a concrete implementation of these two functions but I'm really struggling to understand where to start.
I understand that foo takes a function (a -> (a,b)) and returns a and a list containing b.
And bar takes a function (b -> c) which returns a function (a -> b -> c) which finally returns a and c.
Can anyone show me an example of a concrete implementation?
How do I know where to start with something like this and what goes on the left side of the definition?
You have some misunderstandings there:
I understand that foo takes a function (a -> (a,b)) and returns a and a list containing b.
No, it doesn't return a. It expects it as another argument, in addition to that function.
And bar takes a function (b -> c) which returns a function (a -> b -> c) which finally returns a and c.
Same here. Given g :: a -> b, bar returns a function bar g :: (a -> b -> c) -> a -> c. This function, in turn, given a function h :: (a -> b -> c), returns a function of type a -> c. And so it goes.
It's just like playing with pieces of a puzzle:
foo :: (a -> (a,b)) -> a -> [b]
-- g :: a -> (a,b)
-- x :: a
-- g x :: (a,b)
foo g x = [b] where
(a,b) = g x
bar :: (a -> b) -> (a -> b -> c) -> a -> c
-- g :: a -> b
-- x :: a
-- g x :: b
-- h :: a -> b -> c
-- h x :: b -> c
-- h x (g x) :: c
bar g h x = c where
c = ....
There's not much free choice for us here. Although, there are more ways to get more values of type b, for foo. Instead of ignoring that a in (a,b) = g x, we can use it in more applications of g, so there actually are many more possibilities there, like
foo2 :: (a -> (a,b)) -> a -> [b]
foo2 g x = [b1,b2] where
(a1,b1) = g x
(a2,b2) = g a1
and many more. Still, the types guide the possible implementations. foo can even make use of foo in its implementation, according to the types:
foo3 :: (a -> (a,b)) -> a -> [b]
foo3 g x = b : bs where
(a,b) = g x
bs = ...
So now, with this implementation, the previous two become its special cases: foo g x === take 1 (foo3 g x) and foo2 g x === take 2 (foo3 g x). Having the most general definition is probably best.
In addition to #will-nes's answer, it will be useful to treat (->) as a right-associative infix operator. So something like f: a -> b -> c is the same as f: a -> (b -> c). So this is saying f is a function that takes a value of type a and returns you a value of type b -> c, which is, another function, one that takes a value of type b and returns you a value of type c.
So the types in your example can be re-written as follows
foo :: (a -> (a,b)) -> (a -> [b])
bar :: (a -> b) -> ((a -> (b -> c)) -> (a -> c))
Similarly, you can think of arguments to a function in pieces as well, as being left-associative (like + and -), though there's no explicit operator in this case. foo a b c d e is the same as ((((foo a) b) c) d) e. For example, let's say we have a function f: Int -> Int -> Int (which is the same as f: Int -> (Int -> Int)). You don't have to provide both arguments at once. So you can write g = f 1, which has the type (Int -> Int). And then you can provide an argument to g, like g 2, which has the type Int. f 1 2 and let g = f 1 in g 2 are more or less the same. Here's a more concrete example of how this works:
Prelude> f = (+)
Prelude> g = f 1
Prelude> g 2
3
Prelude> :t f
f :: Num a => a -> a -> a
Prelude> :t g
g :: Num a => a -> a
Prelude> :t g 2
g 2 :: Num a => a
In #will-nes's sample implementation examples, he defines the functions with all of the arguments up front, but you don't have to think of them that way. Just think of f: a -> b -> c as taking a value of type a and returning another function. While most of the methods you encounter will use all of their arguments up-front, there might be cases in which you don't want to do that. Here's an example:
veryExpensive :: A -> B
unstagedFun :: A -> (B -> C) -> C
unstagedFun a f = f (veryExpensive a)
stagedFun :: A -> (B -> C) -> C
stagedFun a = let b = veryExpensive a in \f -> f b
(You can also rewrite the latter as let b = veryExpensive a in ($ b))
Of course, with compiler optimizations, I wouldn't be surprised if the unstaged version staged automatically, but hopefully this offers some motivation for thinking of functions as not having multiple arguments, but rather, as a single argument, but they may return other functions that may themselves return functions (but also only take a single argument).
I was wondering how to write my own sortOn function.
I made a sortBy function and an on function as shown bellow but can't figure out how to combine them and what additional code to add. sortOn is like sortBy but the given function (in here named comp) is applied only once for every element of the list
sortBy :: (a -> a -> Ordering) -> [a] -> [a]
sortBy comp [] = []
sortBy comp [x] = [x]
sortBy comp (x:xs) = insert x (sortBy comp xs)
where
insert x [] = [x]
insert x (y:ys)
| (comp x y == LT) || (comp x y == EQ) = x:y:ys
| otherwise = y:(insert x ys)
on :: (b -> b -> c) -> (a -> b) -> a -> a -> c
on b f x y = b (f x) (f y)
Here's a hint.
If you have a list [a] and you just sort it, the sort function will implicitly make use of the Ord instance for a and specifically the function:
compare :: a -> a -> Ordering
to figure out the relative ordering of pairs of a elements.
Now, if you have a list [a] and a transformation function b, and you want to use sortOn to sort the list of the transformed values, you'll need to figure out the relative ordering of pairs of b elements. How will you do this? Well, you'll implicitly use the Ord instance for b and specifically the function:
compare :: b -> b -> Ordering
In other words, when you try to define:
sortOn :: (Ord b) => (a -> b) -> [a] -> [a]
sortOn f lst = ...
you'll have arguments of type:
f :: a -> b
lst :: [a]
and additional objects of type:
sortBy :: (a -> a -> Ordering) -> [a] -> [a]
on :: (b -> b -> c) -> (a -> b) -> a -> a -> c
compare :: b -> b -> Ordering
Now, can you see how to put them together to define sortOn?
SPOILERS
Further hint: What's the type of compare `on` f?
Further further hint: It's a -> a -> Ordering.
I am currently taking a class in Haskell and am having a bit of trouble understanding how functions are passed as parameters. For this assignment, we were tasked with creating a program that would evaluate expressions. To reduce boiler plating, I wanted to abstract the function by creating a helper function that would take in an operator as an input and return the result
Main Function:
eval :: EDict -> Expr -> Maybe Double
eval _ (Val x) = Just x
eval d (Var i) = find d i
eval d (Add x y) = evalOp d (+) x y
eval d (Mul x y) = evalOp d (*) x y
eval d (Sub x y) = evalOp d (-) x y
Helper Function:
evalOp:: EDict -> ((Num a) => a -> a -> a) -> Expr -> Expr -> Maybe Double
evalOp d op x y =
let r = eval d x
s = eval d y
in case (r, s) of
(Just m, Just n) -> Just (m `op` n)
_ -> Nothing
Other definitions
data Expr
= Val Double
| Add Expr Expr
| Mul Expr Expr
| Sub Expr Expr
| Dvd Expr Expr
| Var Id
| Def Id Expr Expr
deriving (Eq, Show)
type Dict k d = [(k,d)]
define :: Dict k d -> k -> d -> Dict k d
define d s v = (s,v):d
find :: Eq k => Dict k d -> k -> Maybe d
find [] _ = Nothing
find ( (s,v) : ds ) name | name == s = Just v
| otherwise = find ds name
type EDict = Dict String Double
I looked into how +,-, and * are to be passed into other functions and found that these operators are defined by the following definition:
ghci> :t (*)
(*) :: (Num a) => a -> a -> a
However, when I run my code I get the following compilation error:
Illegal polymorphic or qualified type: Num a => a -> a -> a
Perhaps you intended to use RankNTypes or Rank2Types
In the type signature for ‘evalOp’:
evalOp :: EDict
-> ((Num a) => a -> a -> a) -> Expr -> Expr -> Maybe Double
I am not really sure why this is happening as I gave my function the proper parameters as defined by Haskell. Any help would be greatly appreciated as I am still very new to the language.
Right now, your Expr data type is constrained to Double-valued expressions, so there is no need to deal with polymorphism.
evalOp:: EDict -> (Double -> Double -> Double) -> Expr -> Expr -> Maybe Double
evalOp d op x y =
let r = eval d x
s = eval d y
in case (r, s) of
(Just m, Just n) -> Just (m `op` n)
_ -> Nothing
(+) :: Num a => a -> a -> a is a valid argument for evalOp, because its type can be "restricted" to Double -> Double -> Double.
> let f :: Double -> Double -> Double; f = (+)
> f 3 5
8.0
If your expression type were parameterized, then you would put a Num a constraint on your functions (not just on the arguments that involve a, because you want the same a throughout the function).
data Expr a
= Val a
| Add (Expr a) (Expr a)
| Mul (Expr a) (Expr a)
| Sub (Expr a) (Expr a)
| Dvd (Expr a) (Expr a)
| Var Id
| Def Id (Expr a) (Expr a)
deriving (Eq, Show)
type EDict a = Dict String a
evalOp:: Num a => EDict a -> (a -> a -> a) -> Expr a -> Expr a -> Maybe a
evalOp d op x y =
let r = eval d x
s = eval d y
in case (r, s) of
(Just m, Just n) -> Just (m `op` n)
_ -> Nothing
eval :: Num a => EDict a -> Expr a -> Maybe a
eval _ (Val x) = Just x
eval d (Var i) = find d i
eval d (Add x y) = evalOp d (+) x y
eval d (Mul x y) = evalOp d (*) x y
eval d (Sub x y) = evalOp d (-) x y
The error is telling you that you cannot nest a type qualifier inside one of the types in your function chain. Instead, put all of the qualifiers at the beginning of the type signature:
evalOp:: (Num a) => EDict -> (a -> a -> a) -> Expr -> Expr -> Maybe Double
See Haskell - Illegal Polymorphic type? for a more thorough discussion.
I'm attempting problem 11 of "99 Haskell Problems." The problem description is pretty much:
Write a function encodeModified that groups consecutive equal elements, then counts each group, and separates singles from runs.
For example:
Prelude> encodeModified "aaaabccaadeeee"
[Multiple 4 'a',Single 'b',Multiple 2 'c',
Multiple 2 'a',Single 'd',Multiple 4 'e']
Here's my working code:
module Batch2 where
import Data.List -- for `group`
data MultiElement a = Single a | Multiple Int a deriving (Show)
encodeModified :: (Eq a) => [a] -> [MultiElement a]
encodeModified = map f . group
where f xs = case length xs of 1 -> Single (head xs)
_ -> Multiple (length xs) (head xs)
I'd like to take out that pesky repeated (head xs) in the final two lines. I figured I could do so by treating the result of the case clause as a partially applied data constructor, as follows, but no luck:
encodeModified :: (Eq a) => [a] -> [MultiElement a]
encodeModified = map f . group
where f xs = case length xs of 1 -> Single
_ -> Multiple length xs
(head xs)
I also tried putting parenthese around the case clause itself, but to no avail. In that case, the case clause itself failed to compile (throwing an error upon hitting the _ symbol on the second line of the clause).
EDIT: this error was because I added a parenthesis but didn't add an extra space to the next line to make the indentation match. Thanks, raymonad.
I can also solve it like this, but it seems a little messy:
encodeModified :: (Eq a) => [a] -> [MultiElement a]
encodeModified = map (\x -> f x (head x)) . group
where f xs = case length xs of 1 -> Single
_ -> Multiple (length xs)
How can I do this?
The function application operator $ can be used to make this work:
encodeModified = map f . group
where f xs = case length xs of 1 -> Single
_ -> Multiple (length xs)
$ head xs
You could match on xs itself instead:
encodeModified :: (Eq a) => [a] -> [MultiElement a]
encodeModified = map f . group
where f xs = case xs of (x:[]) -> Single x
(x:_) -> Multiple (length xs) x
or more tersely as
encodeModified :: (Eq a) => [a] -> [MultiElement a]
encodeModified = map f . group
where f (x:[]) = Single x
f xs#(x:_) = Multiple (length xs) x
or even
encodeModified :: (Eq a) => [a] -> [MultiElement a]
encodeModified = map f . group
where f as#(x:xs) = case xs of [] -> Single x
_ -> Multiple (length as) x
Admittedly most of these have some repetition, but not of function application.
You could also go with let:
encodeModified :: (Eq a) => [a] -> [MultiElement a]
encodeModified = map f . group
where f xs = let x = head xs
len = length xs in
case len of 1 -> Single x
_ -> Multiple len x
I'm reading learnyouahaskell.com and currently investigating folds. In the book there are these examples:
maximum' :: (Ord a) => [a] -> a
maximum' = foldr1 (\x acc -> if x > acc then x else acc)
reverse' :: [a] -> [a]
reverse' = foldl (\acc x -> x : acc) []
product' :: (Num a) => [a] -> a
product' = foldr1 (*)
filter' :: (a -> Bool) -> [a] -> [a]
filter' p = foldr (\x acc -> if p x then x : acc else acc) []
head' :: [a] -> a
head' = foldr1 (\x _ -> x)
last' :: [a] -> a
last' = foldl1 (\_ x -> x)
I understand all of them except head' and tail'.
It is my understanding that the binary function should be applied to the accumulator and each element in the list in turn, and thus go through all the list. Why does this stop to the head (or tail, respectively)?
I understand _ (underscore) means "whatever" or "I don't care" but how does that stop going through all the list?
A foldr combines two items - the current "running total" sort of item, and the new item.
(\x _ -> x) takes the new item and discards it, retaining the original, so all of the remaining items are ignored.
Let's expand it:
foldr1 (\x _ -> x) [1..100000]
= (\x _ -> x) 1 (foldr (\x _ -> x) [2..100000])
= 1
Since the (foldr (\x _ -> x) [2..100000]) term isn't needed, it isn't evaluated (that's lazy evaluation in action, or rather inaction), so this runs fast.
With (\_ x -> x), the new item is taken and the old one is ignored - this keeps happening until the end of the list, so you get the last element. It doesn't avoid the other ones, it just forgets them all except the last.
A more human-readable name of (\_ x -> x) would refer to the fact that it ignores its first argument and returns its second one. Let's call it secondArg.
foldl1 (\_ x -> x) [1..4]
= let secondArg = (\_ x -> x) in foldl secondArg 1 [2..4]
= foldl (1 `secondArg` 2) [3..4]
= foldl ((1 `secondArg` 2) `secondArg` 3) [4]
= foldl (((1 `secondArg` 2) `secondArg` 3) `secondArg` 4) []
= (((1 `secondArg` 2) `secondArg` 3) `secondArg` 4)
= 4
Let's have a look at the definition of foldr1 first:
foldr1 :: (a -> a -> a) -> [a] -> a
foldr1 f [x] = x
foldr1 f (x : xs) = f x (foldr1 f xs)
Then, consider a call of your function head',
head' :: [a] -> a
head' = foldr1 (\x _ -> x)
to a list, say, [2, 3, 5]:
head' [2, 3, 5]
Now, filling in the right hand-side of head' gives
foldr1 (\x _ -> x) [2, 3, 5]
Recall that [2, 3, 5] is syntactic sugar for (2 : 3 : 5 : []). So, the second case of the definition of foldr1 applies and we yield
(\x _ -> x) 2 (foldr1 (\x _ -> x) (3 : 5 : [])
Now, reducing the applications results in 2 getting bound to x and foldr1 (\x _ -> x) (3 : 5 : []) getting bound to the ignored parameter _. What is left is the right-hand side of the lambda-abstraction with x replaced by 2:
2
Note that lazy evaluation makes that the ignored argument foldr1 (\x _ -> x) (3 : 5 : []) is left unevaluated and so—and this hopefully answers your question—the recursion stops before we have processed the remainder of the list.