在 Haskell 中不存在键的查找中使用 Either
Using Either in a lookup where no key exists in Haskell
我正在关注这个:
我正在尝试通过 headers 中的变量名从 CSV 中获取一列数据,前面部分给出了 。
这是我的代码:
import Text.CSV
import Data.List
import Data.Maybe
dat <- parseCSVFromFile "/home/user/data.csv"
headers = head dat
records = tail dat
indexField :: [[Field]] -> Int -> [Field]
indexField records index = map (\x -> x !! index) records
有效:
Prelude> indexField records 0
[1,2,3]
和headers如下:
Prelude> headers
["id", "category", "value"]
我有以下按字段索引 name 而不是 index
indexFieldbyName :: [[Field]] -> String -> [Field]
indexFieldbyName records indexName = indexField records (fromJust (elemIndex indexName headers))
这也有效:
Prelude> indexFieldbyName records "id"
[1,2,3]
但是,当在 headers
:
中找不到密钥时,我希望它能提供更多信息
Prelude> indexFieldbyName records "meow"
Maybe.fromJust: Nothing
这是我的尝试:
indexFieldbyName2 :: [[Field]] -> String -> Either String [Field]
indexFieldbyName2 records indexName = indexField records index
where index = case (elemIndex indexName headers) of
Just v -> Right (v)
Nothing -> Left ("Index not found")
Parse error (line 31, column 5): parse error on input ‘Just’
和
indexFieldbyName3 :: [[Field]] -> String -> Either String [Field]
indexFieldbyName3 records indexName = indexField records index
where index = case v of
Just (elemIndex indexName headers) -> Right (v)
Nothing -> Left ("Index not found")
Parse error (line 44, column 4): parse error on input ‘Just’
indexFieldbyName4 :: [[Field]] -> String -> Either String [Field]
indexFieldbyName4 records indexName = indexField records index
where index = case v of
Just v -> Right (elemIndex indexName headers)
Nothing -> Left ("Index not found")
Parse error (line 37, column 4): parse error on input ‘Just’
以上是缩进问题,just
必须在 case
的右边。现在我有:
indexFieldbyName2' :: [[Field]] -> String -> Either String [Field]
indexFieldbyName2' records indexName = indexField records index
where index = case (elemIndex indexName headers) of
Just v -> Right (v)
Nothing -> Left ("Index not found")
<interactive>:4:39: error:
• Couldn't match expected type ‘Either String [Field]’ with actual type ‘[Field]’
• In the expression: indexField records index
In an equation for ‘indexFieldbyName2’:
indexFieldbyName2 records indexName
= indexField records index
where
index
= case (elemIndex indexName headers) of
Just v -> Right (v)
Nothing -> Left ("Index not found")
<interactive>:4:58: error:
• Couldn't match expected type ‘Int’ with actual type ‘Either String Int’
• In the second argument of ‘indexField’, namely ‘index’
In the expression: indexField records index
In an equation for ‘indexFieldbyName2’:
indexFieldbyName2 records indexName
= indexField records index
where
index
= case (elemIndex indexName headers) of
Just v -> Right (v)
Nothing -> Left ("Index not found")
清理你的函数,你有:
indexFieldbyName2' :: [[Field]] -> String -> Either String [Field]
indexFieldbyName2' records indexName = indexField records index
where index = case elemIndex indexName headers of
Just v -> Right v
Nothing -> Left "Index not found"
index
的类型是 Either String Int
而 indexField records
需要 Int
。您可以编写另一个 case
,或使用 fmap
,但您可能会发现代码更易读:
indexFieldbyName3 :: [[Field]] -> String -> Either String [Field]
indexFieldbyName3 records indexName =
case elemIndex indexName headers of
Just v -> Right (indexField records v)
Nothing -> Left "Index not found"
或者使用更多辅助函数,例如 maybe
而不是 case
:
indexFieldbyName4 :: [[Field]] -> String -> Either String [Field]
indexFieldbyName4 records indexName =
let midx = elemIndex indexName headers
err = Left "Index not found"
in maybe err (Right . indexField records) midx
N.B。键入的答案,未经测试。
嗯,在讨论中解决了。
原来有两个问题:
第一个缩进是错误的。在 haskell wikibook 有一点阅读。简而言之,当代码与 where
在同一行时,以下行需要从与 where 之后的第一个单词相同的字符开始。但是由于 Just/Nothing 属于上一行中的情况,因此需要另一层缩进。
第二个是在处理仿函数时经常发生的事情。 return 类型不再是 Int
而是 f Int
。所以indexField records index
需要改写为fmap (indexField records) index
。或者因为这是一个常见的模式,所以它有一个运算符 <$>
所以 (indexField records) <$> index
。 (想想你也可以将原始语句写成 (indexField records) $ index
)。
我正在关注这个:
我正在尝试通过 headers 中的变量名从 CSV 中获取一列数据,前面部分给出了
这是我的代码:
import Text.CSV
import Data.List
import Data.Maybe
dat <- parseCSVFromFile "/home/user/data.csv"
headers = head dat
records = tail dat
indexField :: [[Field]] -> Int -> [Field]
indexField records index = map (\x -> x !! index) records
有效:
Prelude> indexField records 0
[1,2,3]
和headers如下:
Prelude> headers
["id", "category", "value"]
我有以下按字段索引 name 而不是 index
indexFieldbyName :: [[Field]] -> String -> [Field]
indexFieldbyName records indexName = indexField records (fromJust (elemIndex indexName headers))
这也有效:
Prelude> indexFieldbyName records "id"
[1,2,3]
但是,当在 headers
:
Prelude> indexFieldbyName records "meow"
Maybe.fromJust: Nothing
这是我的尝试:
indexFieldbyName2 :: [[Field]] -> String -> Either String [Field]
indexFieldbyName2 records indexName = indexField records index
where index = case (elemIndex indexName headers) of
Just v -> Right (v)
Nothing -> Left ("Index not found")
Parse error (line 31, column 5): parse error on input ‘Just’
和
indexFieldbyName3 :: [[Field]] -> String -> Either String [Field]
indexFieldbyName3 records indexName = indexField records index
where index = case v of
Just (elemIndex indexName headers) -> Right (v)
Nothing -> Left ("Index not found")
Parse error (line 44, column 4): parse error on input ‘Just’
indexFieldbyName4 :: [[Field]] -> String -> Either String [Field]
indexFieldbyName4 records indexName = indexField records index
where index = case v of
Just v -> Right (elemIndex indexName headers)
Nothing -> Left ("Index not found")
Parse error (line 37, column 4): parse error on input ‘Just’
以上是缩进问题,just
必须在 case
的右边。现在我有:
indexFieldbyName2' :: [[Field]] -> String -> Either String [Field]
indexFieldbyName2' records indexName = indexField records index
where index = case (elemIndex indexName headers) of
Just v -> Right (v)
Nothing -> Left ("Index not found")
<interactive>:4:39: error:
• Couldn't match expected type ‘Either String [Field]’ with actual type ‘[Field]’
• In the expression: indexField records index
In an equation for ‘indexFieldbyName2’:
indexFieldbyName2 records indexName
= indexField records index
where
index
= case (elemIndex indexName headers) of
Just v -> Right (v)
Nothing -> Left ("Index not found")
<interactive>:4:58: error:
• Couldn't match expected type ‘Int’ with actual type ‘Either String Int’
• In the second argument of ‘indexField’, namely ‘index’
In the expression: indexField records index
In an equation for ‘indexFieldbyName2’:
indexFieldbyName2 records indexName
= indexField records index
where
index
= case (elemIndex indexName headers) of
Just v -> Right (v)
Nothing -> Left ("Index not found")
清理你的函数,你有:
indexFieldbyName2' :: [[Field]] -> String -> Either String [Field]
indexFieldbyName2' records indexName = indexField records index
where index = case elemIndex indexName headers of
Just v -> Right v
Nothing -> Left "Index not found"
index
的类型是 Either String Int
而 indexField records
需要 Int
。您可以编写另一个 case
,或使用 fmap
,但您可能会发现代码更易读:
indexFieldbyName3 :: [[Field]] -> String -> Either String [Field]
indexFieldbyName3 records indexName =
case elemIndex indexName headers of
Just v -> Right (indexField records v)
Nothing -> Left "Index not found"
或者使用更多辅助函数,例如 maybe
而不是 case
:
indexFieldbyName4 :: [[Field]] -> String -> Either String [Field]
indexFieldbyName4 records indexName =
let midx = elemIndex indexName headers
err = Left "Index not found"
in maybe err (Right . indexField records) midx
N.B。键入的答案,未经测试。
嗯,在讨论中解决了。
原来有两个问题:
第一个缩进是错误的。在 haskell wikibook 有一点阅读。简而言之,当代码与 where
在同一行时,以下行需要从与 where 之后的第一个单词相同的字符开始。但是由于 Just/Nothing 属于上一行中的情况,因此需要另一层缩进。
第二个是在处理仿函数时经常发生的事情。 return 类型不再是 Int
而是 f Int
。所以indexField records index
需要改写为fmap (indexField records) index
。或者因为这是一个常见的模式,所以它有一个运算符 <$>
所以 (indexField records) <$> index
。 (想想你也可以将原始语句写成 (indexField records) $ index
)。