[英]Beginner Haskell problems (No instance for … arising from)
我最近開始學習Haskell,我正在嘗試重寫我在Haskell中使用python進行訪談時所做的一些事情。 我正在嘗試將字符串從camel case轉換為下划線(“myVariableName” - >“my_variable_name”),如果第一個字符為大寫,則會拋出錯誤。
這就是我所擁有的:
import qualified Data.Char as Char
translate_java :: String -> String
translate_java xs = translate_helper $ enumerate xs
where
translate_helper [] = []
translate_helper ((a, num):xs)
| num == 1 and Char.isUpper a = error "cannot start with upper"
| Char.isUpper a = '_' : Char.toLower a : translate_helper xs
| otherwise = a : translate_helper xs
enumerate :: (Num b, Enum b) => [a] -> [(a,b)]
enumerate xs = zip xs [1..]
我意識到我很可能會以一種奇怪的方式解決這個問題,而且我喜歡有關更好的方法來實現這一點的建議,但我也希望能夠編譯它。 這是我現在得到的錯誤:
Prelude> :r
[1 of 1] Compiling Main ( translate.hs, interpreted )
translate.hs:4:20:
No instance for (Num
(([Bool] -> Bool) -> (Char -> Bool) -> Char -> t))
arising from a use of `translate_helper' at translate.hs:4:20-35
Possible fix:
add an instance declaration for
(Num (([Bool] -> Bool) -> (Char -> Bool) -> Char -> t))
In the first argument of `($)', namely `translate_helper'
In the expression: translate_helper $ enumerate xs
In the definition of `translate_java':
translate_java xs
= translate_helper $ enumerate xs
where
translate_helper [] = []
translate_helper ((a, num) : xs)
| num == 1 and Char.isUpper a
= error "cannot start with upper
"
| Char.isUpper a
= '_' : Char.toLower a : transla
te_helper xs
| otherwise = a : translate_help
er xs
Failed, modules loaded: none.
對這里發生的事情的任何解釋都會很棒。 我真的不明白“(Num(([Bool] - > Bool) - >(Char - > Bool) - > Char - > t))”來自。 我認為translate_helper的類型聲明類似於[(a,b)] - > [a]?
你必須更換and
通過&&
。 第一個是一個函數(前綴),它接收一個布爾值列表並計算它們的全部。 第二個是真正的邏輯和。 但錯誤消息有點令人困惑。 每當我收到如此奇怪的錯誤消息時,我通常會開始使用類型簽名來注釋我的代碼。 然后編譯器能夠為您提供更詳細的錯誤描述。
其他人提到你應該使用(&&)
代替and
,所以我會回答你的另一個問題:不,我不認為你會以一種奇怪的方式解決這個問題。
但是......我覺得它可以更優雅!
translate_java (x:xs) | isUpper x = error "cannot start with an upper"
translate_java xs = concatMap translate xs where
translate x = ['_' | isUpper x] ++ [toLower x]
這里有一些有趣的事情:
concatMap
函數在很多情況下非常方便。 它只是一張map
后面是一個concat
。 如果我自己寫這篇文章,我可能會使用xs >>= translate
。 ['_' | isUpper x]
['_' | isUpper x]
是一個列表理解; 這是一個可愛的習慣用法,用於制作一個包含0或1個元素的列表,具體取決於謂詞是否成立。 除此之外,代碼應該是相當不言自明的。
問題是這樣的:
| num == 1 and Char.isUpper a = ...
and
不是中綴運營商; 相反它是一個功能:
and :: [Bool] -> Bool
所以它解釋1 and Char.isUpper a
將三個參數應用於“function” 1
。 請改用&&
。
錯誤消息來自解釋數字的方式。 數字,比方說, 1
實際上是多態的; 它獲得的具體類型取決於所需的類型。 這就是為什么你可以說x+1
,無論x
是整數還是雙精度,它都能正常工作。 因此編譯器推斷1
的類型需要是一個三參數函數,然后嘗試找到匹配的數字類型,以便它可以將1
轉換為該類型(當然,失敗)。
這是我的解決方案。 它不像Daniel Wagner使用concatMap和列表理解所給出的那樣精湛,但對初學者來說可能更容易理解。
conv :: String -> String
conv [] = []
conv s@(x:xs) = if Char.isUpper x
then error "First character cannot be uppercase"
else change s
change :: String -> String
change [] = []
change (x:xs) = if Char.isUpper x
then '_' : Char.toLower x : change xs
else x : change xs
函數conv實際上只是檢查你的標准,即第一個字符不能是大寫的,如果不是,它將字符串交給函數更改,這就完成了工作。 它逐個遍歷所有字符,構建一個列表,如果字符是大寫的,它會添加一個下划線,后跟字符的小寫版本,否則如果字符已經是小寫,則只需按原樣添加即可。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.