William
William

Reputation: 109

How to convert a String to lowercase using lambda expressions

I want to know how to convert a string to lowercase using the ToLower function (Char -> Char).

This is the code I have so far:

let newlist = (\(h:t) -> c (h) ++ newlist (\c -> toLower c)

I can't see how to do it without using recursion, which I don't know how to use in a lambda expression

Upvotes: 10

Views: 16728

Answers (3)

mnoronha
mnoronha

Reputation: 2625

It would be easier to not use a lambda expression considering you can eta-reduce to not explicitly name the variable your function accepts. For example you could use a list comprehension:

import Data.Char

lowerString str = [ toLower loweredString | loweredString <- str]

Which you would call as:

ghci> lowerString "Hello"
hello

Alternatively, you could use map:

lowerString = map toLower

If you insist on using a lambda expression, it would look something like this:

import Data.Char

lowerString = \x -> map toLower x

Which again, is not as nice.

Upvotes: 22

Dave Compton
Dave Compton

Reputation: 1441

This may be more trouble than it's worth but you can use the fix function to recursively call a lambda function.

fix :: (a -> a) -> a
fix f = let x = f x in x

The following code uses the same method used on this page : https://www.vex.net/~trebla/haskell/fix.xhtml to transition from a non-lambda version to a lambda version to (eventually) using fix to recursively call a lambda function without introducing a new variable

import Data.Char (toLower)
import Control.Monad.Fix (fix)

main :: IO ()
main = do 
    -- calling non lambda version
    let newlist1 s = if null s then [] else toLower (head s) : newlist1 (tail s)
    print $ newlist1 "Hello"

    -- calling lambda version
    let newlist2 = \s -> if null s then [] else toLower (head s) : newlist2 (tail s)
    print $ newlist2 "Hello"

    -- defining lambda version locally
    -- ( at this point the scope of newlist3 is local to the let statement )
    print $ (let newlist3 = \s -> if null s then [] else toLower (head s) : newlist3 (tail s) in newlist3 ) "Hello"

    -- making function an argument to be called recursively
    print $ (let newlist3 = (\v -> \s -> if null s then [] else toLower (head s) : v (tail s)) newlist3 in newlist3 ) "Hello"

    -- isolating function to be "fixed".
    let f = (\v -> \s -> if null s then [] else toLower (head s) : v (tail s))
    print $ (let newlist3 =  f newlist3 in newlist3 ) "Hello"

    -- using fix = let x = f x in x
    print $ (fix f) "Hello"

    -- f2 is slightly simpler version of f
    let f2 = (\v s -> if null s then [] else toLower (head s) : v (tail s))
    print $ (fix f2) "Hello"

    -- inlining f2 to get recursive call to lambda 
    print $ (fix (\v s -> if null s then [] else toLower (head s) : v (tail s))) "Hello"

Upvotes: 0

Bargros
Bargros

Reputation: 531

With a lambda expression you'd still need to recursively check each character of the string, or you could use map which is still a recursive function that applies the function (a -> b) to every element in the list, for example:

  newList [] = []
  newList xs = (\(y:ys) -> if x `elem` ['A'..'Z'] then toLower y : newList ys else y : newList ys) xs

With map is actually much simpler due to reasons explained in the first paragraph, check mnoronha's answer as he already gave you the answer, but that's if you're thinking of using map in conjunction with toLower.

This is an example without a lambda expression, which requires you to import 2 functions from Data.Char, recursively check the rest of the string and replace each character with its lower case version.

newList :: String -> String
newList [] = []
newList (x:xs) = if x `elem` ['A'..'Z'] 
               then chr (ord x + 32) : newList xs 
               else x : newList xs  

or with guards

newList :: String -> String
newList [] = []
newList (x:xs)
    | x `elem` ['A'..'Z'] = chr (ord x + 32) : newList xs 
    | otherwise = x : newList xs 

Upvotes: 2

Related Questions