Here is an example of what I wanted to do.
let b = ["this","is","a","test!"]
"xx" ++ (b!!3)
This will give me "xxtest!"
Basically if the list contains any string with an exclamation mark then "xx" will be added to this specific string. My questions is how to implement this into a correct function.
Currently I got this
replaceElement [] = []
replaceElement (x:xs) =
if '!' `elem` x
then ["xx"] ++ x : replaceElement xs
else x: replaceElement xs
But this function will just add "xx" into list as an element, it won't be added to the specific string in the list. How can I use "xx" ++ (b!!x) where x is the position of the string with an exclamation mark.
The expression
["xx"] ++ x : replaceElement xs
is actually parsed as
["xx"] ++ (x : replaceElement xs)
which does just what you described: inserts "xx" into the resulting list. What you want to do instead, is:
("xx" ++ x) : replaceElement xs
The crucial thing is how ["xx"] ++ x : replaceElement xs is parsed. This is determined by the fixities of the operators:
GHCi, version 7.10.2: http://www.haskell.org/ghc/ :? for help
Prelude> :info :
-- ...
infixr 5 :
Prelude> :i ++
(++) :: [a] -> [a] -> [a] -- Defined in ‘GHC.Base’
infixr 5 ++
So, both : and ++ are right-associative operators, with the same precedence. Right-associative means, a : b : c is parsed as a : (b : c), instead of (a : b) : c (as would be the case for left-associative infixl). Due to the equal precedence, this still holds if you mix : and ++, i.s.
["xx"] ++ x : replaceElement xs ≡ ["xx"] ++ (x : replaceElement xs)
IOW, you're just prepending ["xx"] to the whole result, but the individual elements never get in contact with "xx". To achieve that, you need to group "xx" with x. The extra brackets are unnecessary then (in fact these could have tipped you off: wrapping "xs" in an extra layer means you're not working of the string-level anymore as intended, but on the list-of-string level).
A better alternative would of course be to not do any manual recursion: you're simply applying the same operation to all elements of a list; that's what map is there for:
replaceElement = map $ \x -> if '!'`elem`x
then "xx"++x
else x
You may also use map with a helper function like;
addxx :: [String] -> [String]
addxx = map checkBang
where checkBang s | last s == '!' = "xx" ++ s
| otherwise = s
Related
With dependent types, you can either capture function properties in the type signature, like in concatenation with length-indexed lists
(++) : Vect m a -> Vect n a -> Vect (m + n) a
or you can not use dependent types in your signature, like concatenation with standard lists
(++) : List a -> List a -> List a
and write proofs about (++)
appendAddsLength : (xs, ys : List a) -> length (xs ++ ys) = length xs + length ys
lengthNil : length [] = 0
lengthCons : (x : a) -> (xs : List a) -> length (x :: xs) = length xs + 1
Is there any difference between these approaches beyond ergonomics?
The most obvious difference is that, with (++) on Vects, the length is statically known: you can operate on it at compile time. Moreover, you don't need to write any additional proofs in order to ensure that (++) has the expected behavior on Vects, whereas you need to do it for Lists.
That is, (++) on Vect is correct by construction. The compiler will always enforce the desired properties, whether you like it or not, and without the user taking any additional action.
It's important to note that length xs is not really interchangeable with the statically-known size in general. On these data types, length is a function which actually re-computes the length of a List or Vect by walking through it and incrementing a counter:
libs/prelude/Prelude/Types.idr:L403-L407
namespace List
||| Returns the length of the list.
public export
length : List a -> Nat
length [] = Z
length (x :: xs) = S (length xs)
libs/base/Data/Vect.idr:25-28
public export
length : (xs : Vect len elem) -> Nat
length [] = 0
length (_::xs) = 1 + length xs
Even with Vect, the length built into to the type by construction, but the result of applying the length function to a List or Vect is not fundamental at all. In fact, Data.Vect contains a proof that Data.Vect.length that applying length to a Vect n t always returns n:
libs/base/Data/Vect.idr:30-34
||| Show that the length function on vectors in fact calculates the length
export
lengthCorrect : (xs : Vect len elem) -> length xs = len
lengthCorrect [] = Refl
lengthCorrect (_ :: xs) = rewrite lengthCorrect xs in Refl
Using the above proof, we can assert statically, without actually executing length, that the result of length is propositionally equal to the statically-known length of the Vect. But this assurance is not available for List. And it's much more cumbersome to work with in general, likely requiring the use of with ... proof and rewrite a lot more than just using the correct-by-construction type.
In Haskell, f $ g a = f (g a). Is there a right-associated operator like that in Unison?
There are a few options.
You can use let. For example, f let g a is the same as f (g a). This is because let opens a block, which is a sequence of statements. In this case the only statement in the block is the expression g a which becomes the value the block returns. So you could write e.g.
isSome let head let List.map increment [1,2,3]
There is a function application operator:
(base.Function.<|) : (a ->{e} b) -> a ->{e} b
so you could write f <| g a. However, Unison does not have any operator precedence rules, so all operators associate to the left. So if you want to do nested applications like
isSome <| (head <| List.map increment [1,2,3])
you will need to use parentheses anyway. However, since all operators associate to the left, you can just use the |> operator instead:
(base.Function.|>) : a -> (a ->{e} b) ->{e} b
Then you can write (flipping the order of the functions):
[1,2,3] |> List.map increment |> head |> isSome
You can use function composition:
(base.Function.<<) : (b ->{e} c) -> (a ->{e} b) -> a ->{e} c
This lets you write
isSome << head << List.map increment <| [1,2,3]
Which is equivalent to the Haskell expression:
isJust . listToMaybe . map (+1) $ [1,2,3]
I'm trying to define the map function using foldr
I have found the two following solutions, however I'm not quite sure how they are working.
map' :: (a -> b) -> [a] -> [b]
map' f = foldr ((:) . f) []
map'' :: (a -> b) -> [a] -> [b]
map'' f = foldr (\x xs -> f x : xs) []
I'm quite new to Haskell and foldr, so I'm struggling to understand what ((:) . f) in the first solution and what (\x xs -> f x : xs) in the second solution do.
I also don't get how foldr is able handle the empty list case.
It would be much appreciated if I could get a simple step by step explanation of this, in layman's terms.
Both (\x xs -> f x : xs) and (:) . f mean the same thing. They're both functions that take two arguments, apply f to the first argument, and then cons that onto the second argument.
So what does foldr do when given an empty list? It simply returns the starting value, which in these examples is [].
Here is the implementation of foldr from Hackage:
foldr k z = go
where
go [] = z
go (y:ys) = y `k` go ys
I want to write a function that takes a mathematical function (/,x,+,-), a number to start with and a list of numbers. Then, it's supposed to give back a list.
The first element is the starting number, the second element the value of the starting number plus/minus/times/divided by the first number of the given list. The third element is the result of the previous result plus/minus/times/divided by the second result of the given list, and so on.
I've gotten everything to work if I tell the code which function to use but if I want to let the user input the mathematical function he wants, there are problems with the types. Trying :t (/) for example gives out Fractional a => a -> a -> a, but if you put that at the start of your types, it fails.
Is there a specific type to distinguish these functions (/,x,+,-)? Or is there another way to write this function succesfully?
prefix :: (Fractional a, Num a) => a -> a -> a -> a -> [a] -> [a]
prefix (f) a b = [a] ++ prefix' (f) a b
prefix' :: (Fractional a, Num a) => a -> a -> a -> a -> [a] -> [a]
prefix' (z) x [] = []
prefix' (z) x y = [x z (head y)] ++ prefix' (z) (head (prefix' (z) x y)) (tail y)
A right solution would be something like this:
prefix (-) 0 [1..5]
[0,-1,-3,-6,-10,-15]
Is there a specific type to distinguish these functions (/,*,+,-)?
I don't see a reason to do this. Why is \x y -> x+y considered "better" than \x y -> x + y + 1. Sure adding two numbers is something that most will consider more "pure". But it is strange to restrict yourself to a specific subset of functions. It is also possible that for some function \x y -> f x y - 1 "happens" to be equal to (+), except that the compiler can not determine that.
The type checking will make sure that one can not pass functions that operate on numbers, given the list contains strings, etc. But deliberately restricting this further is not very useful. Why would you prevent programmers to use your function for different purposes?
Or is there another way to write this function succesfully?
What you here describe is the scanl :: (b -> a -> b) -> b -> [a] -> [b] function. If we call scanl with scanl f z [x1, x2, ..., xn], then we obtain a list [z, f z x1, f (f z x1) x2, ...]. scanl can be defined as:
scanl :: (b -> a -> b) -> b -> [a] -> [b]
scanl f = go
where go z [] = [z]
go z (x:xs) = z : go (f z x) xs
We thus first emit the accumulator (that starts with the initial value), and then "update" the accumulator to f z x with z the old accumulator, and x the head of the list, and recurse on the tail of the list.
If you want to restrict to these four operations, just define the type yourself:
data ArithOp = Plus | Minus | Times | Div
as_fun Plus = (+)
as_fun Minus = (-)
as_fun Times = (*)
as_fun Div = (/)
A while ago, I asked a question about $, and got useful answers -- in fact, I thought I understood how to use it.
It seems I was wrong :(
This example shows up in a tutorial:
instance Monad [] where
xs >>= f = concat . map f $ xs
I can't for the life of me see why $ was used there; ghci isn't helping me either, as even tests I do there seem to show equivalence with the version that would simply omit the $. Can someone clarify this for me?
The $ is used here because it has lower precedence than normal function application.
Another way to write this code is like so:
instance Monad [] where
xs >>= f = (concat . map f) xs
The idea here is to first construct a function (concat . map f) and then apply it to its argument (xs). As shown, this can also be done by simply putting parenthesis around the first part.
Note that omitting the $ in the original definition is not possible, it will result in a type error. This is because the function composition operator (the .) has a lower precedence than normal function application effectively turning the expression into:
instance Monad [] where
xs >>= f = concat . (map f xs)
Which doesn't make sense, because the second argument to the function composition operator isn't a function at all. Although the following definition does make sense:
instance Monad [] where
xs >>= f = concat (map f xs)
Incidentally, this is also the definition I would prefer, because it seems to me to be a lot clearer.
I'd like to explain why IMHO this is not the used style there:
instance Monad [] where
xs >>= f = concat (map f xs)
concat . map f is an example of so-called pointfree-style writing; where pointfree means "without the point of application". Remember that in maths, in the expression y=f(x), we say that f is applied on the point x. In most cases, you can actually do a final step, replacing:
f x = something $ x
with
f = something
like f = concat . map f, and this is actually pointfree style.
Which is clearer is arguable, but the pointfree style gives a different point of view which is also useful, so sometimes is used even when not exactly needed.
EDIT: I have replaced pointless with pointfree and fixed some examples, after the comment by Alasdair, whom I should thank.
The reason $ is used here is doe to the type signature of (.):
(.) :: (b -> c) -> (a -> c) -> a -> c
Here we have
map f :: [a] -> [[b]]
and
concat :: [[b]] -> [b]
So we end up with
concat . map f :: [a] -> [b]
and the type of (.) could be written as
(.) :: ([[b]] -> [b]) -> ([a] -> [[b]]) -> [a] -> [b]
If we were to use concat . map f xs, we'd see that
map f xs :: [[b]]
And so cannot be used with (.). (the type would have to be (.) :: (a -> b) -> a -> b