我正试图编写一个函数score :: Char -> Int
,将字符转换为其分数。每一个以分数1开头的字母;1如果是元音,则加到字符的分数中(a, e, i, o, u)和1如果是大写字符则加到分数中;一个字符这不是一个得分0的字母。例如,
score 'A' == 3
score 'a' == 2
score 'B' == 2
score 'b' == 1
score '.' == 0
这是我到目前为止的代码:
n :: Int -> Int
n = 0
isVowel :: Char -> Char
isVowel x = [if x == 'a' || x == 'e' || x == 'i' ||
x == 'o' || x == 'u' then x else x]
score :: Char -> Int
score x =
[if isAlpha x then n+1 else n ]
[if isUpper x then n+1 else n ]
[if isVowel x then n+1 else n ]
这段代码肯定有问题,但我找不到。具体来说,有没有办法写一个检测元音的函数?我甚至不确定我写的那个是对的。或者我把isVowel
的类型改成Char -> Bool
如果是isVowel = True
,那还行吗?我将感谢您提供的任何帮助
你在(单例)列表中编写表达式。此外,您的isVowel
应该返回Bool
。因此,我们可以这样实现:
isVowel :: Char ->Bool
isVowel x = x == 'a' || x == 'e' || x == 'i' || x == 'o' || x == 'u'
但是您忘记了大写元音(AEIOU)。我们可以用elem
检查将其写得更紧凑:
isVowel :: Char -> Bool
isVowel x = x`elem`"aeiouAEIOU"
或甚至与中缀操作符的部分连在一起:
isVowel :: Char -> Bool
isVowel = (`elem`"aeiouAEIOU")
在你的score
函数中,你似乎使用了一个变量n
,但该变量没有在某个地方定义,而且在Haskell中所有变量都是不可变的:一旦分配了一个值,你就不能再改变它的值。
我们可以通过将三项相加来计算分数:
score :: Char -> Int
score x = (if isAlpha x then 1 else 0) + (if isUpper x then 1 else 0) + (if isVowel x then 1 else 0)
由于Bool
是Enum
的成员如果False
映射到0
,True
映射到1
,我们可以使用fromEnum :: Enum a => a -> Int
要自动进行转换:
score :: Char -> Int
score x = fromEnum (isAlpha x) + fromEnum (isUpper x) + fromEnum (isVowel x)
或者,就像@leftroundabout说的:我们也可以使用列表推导和检查列表,所以:
score :: Char -> Int
score x = length [ 1 |p<- [isAlpha, isUpper, isVowel],p x]
你写:
n :: Int -> Int
n = 0
n
定义为0
。它将永远是0
。我们不能改变它,我们已经这样定义了。
这也不是一个函数,它只是Int
。
n :: Int
n = 0
isVowel :: Char -> Char
isVowel x = [if x == 'a' || x == 'e' || x == 'i' ||
x == 'o' || x == 'u' then x else x]
显然有些部分很好,但首先,为什么要用括号?我们根本不需要他们。第二,返回类型应该是Bool
:
isVowel :: Char -> Bool
isVowel x = if x == 'a' || x == 'e' || x == 'i' ||
x == 'o' || x == 'u' then True else False
但是随后if
只是原样返回它的测试,所以也不需要它:
isVowel :: Char -> Bool
isVowel x = x == 'a' || x == 'e' || x == 'i' ||
x == 'o' || x == 'u'
最后,score
:
score :: Char -> Int
score x =
[if isAlpha x then n+1 else n ]
[if isUpper x then n+1 else n ]
[if isVowel x then n+1 else n ]
这里是n+1 == 0+1 == 1
,所以不需要n
。事实上,
score :: Char -> Int
score x = sum (
[1 | isAlpha x ] ++
[1 | isUpper x ] ++
[1 | isVowel x ] )
是我们所需要的。
当你写下
score x =
[if isAlpha x then n+1 else n]
[if isUpper x then n+1 else n]
[if isVowel x then n+1 else n]
你可能有一点像Python
def score(x):
n = 0
if isAlpha(x): n+=1
if isUpper(x): n+=1
if isVowel(x): n+=1
return n
正如其他答案所指出的那样,这可以-而且应该-仅用sum
或length
来表示,但在更一般的情况下(对变量进行顺序类似的更新),您将使用折叠:
import Data.List
score x = foldl' (n p -> if p x then n+1 else n) 0
[isAlpha, isUpper, isVowel]
或者
score x = foldl' (flip id) 0
[ n -> if isAlpha x then n+1 else n
, n -> if isUpper x then n+1 else n
, n -> if isVowel x then n+1 else n
]
甚至可以(尽管在这种情况下不推荐)通过在状态单子中工作来使它看起来完全命令式:
import Control.Monad
import Control.Monad.Trans.State
score = (`execState`0) $ do
when (isAlpha x) $ modify (+1)
when (isUpper x) $ modify (+1)
when (isVowel x) $ modify (+1)