Invoking nested functions in Haskell

 ̄綄美尐妖づ 提交于 2020-01-06 05:47:09

问题


I have defined a function called initials inside a function called person, but I can't figure out how to call initials outside of person:

main =
    --I attempted to print the output of the initials function here.
    (putStrLn ((person "firstName" "lastName") . initials)) --Not in scope: `initials'
    --If this function call worked correctly, the output would be "f.l.".

person firstName lastName =
    firstName ++ ["."] ++ lastName
    where
        fullName = firstName ++ " " ++ lastName
        firstInitial = firstName !! 0
        lastInitial = lastName !! 0
        initials = [firstInitial] ++ "." ++ [lastInitial] ++ "."

Is it possible to invoke the initials function inside the main function, even though it is defined inside the person function?


回答1:


You're misunderstanding what where does: it just scopes definitions, meaning they can only be used in the item they are attached to, in this case, initials can only be used in person.

In other words, you are defining a function person :: String -> String -> [String] (taking two strings and returning a list of them), where the internal implementation details of this function include some (unused) value called initials. It is not like a struct or class in other languages, where initials is some value that all persons can access. (And anyway person is just returning a list of strings, not a new type.) Also, . is not a field accessor, it is just a convenient helper for function composition.

It seems like you might be wanting to make a Person data type, something like

data Person = Person { firstName :: String, lastName :: String }

This is defining Person via "record syntax".

Now, you can write a function that takes a Person and returns their initials:

-- using pattern matching
initials (Person {firstName = f, lastName = l}) =
    [f !! 0] ++ "." ++ [l !! 0] ++ "."

-- or, using the accessors implicitly defined via record syntax
initials p = [firstName p !! 0] ++ "." ++ [lastName p !! 0] ++ "."

This is used like

putStrLn (initials (Person { firstName = "first", lastName = "last" }))

-- or, just using positional arguments (which still work with record syntax)
putStrLn (initials (Person "first" "last"))



回答2:


initials isn't a function. It's just a variable you've defined in the body of person. If you just want to display the initials, that's straightforward:

main =
    putStrLn (initials "John" "Doe")

initials :: String -> String -> String
initials firstName lastName = 
    [firstInitial] ++ "." ++ [lastInitial] ++ "."
    where
        firstInitial = firstName !! 0
        lastInitial  =  lastName !! 0 

In GHCi:

*Main> main
J.D.

Or, at a slightly higher level of abstraction,

main =
    putStrLn (initials ["John", "Queue", "Public"])

initials :: [String] -> String
initials (name:names) = [name !! 0] ++ "." ++ initials names
initials _            = ""

In GHCi:

*Main> main
J.Q.P.

I don't fully understand why you've written the person function - it returns "John.Doe" for inputs "John" and "Doe", but I don't see how that is useful for printing the initials "J.D.".



来源:https://stackoverflow.com/questions/24235757/invoking-nested-functions-in-haskell

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!