无法在Haskell中形成元组列表

时间:2018-03-23 03:13:16

标签: haskell tuples

因此,我的代码尝试读取const { Seeder } = require('mongoose-data-seed'); const mongoose = require('mongoose'); const Resource = require('../models/resource'); const SeedingHelper = require('../helpers/seeding-helper'); const { Types: { ObjectId } } = mongoose; class ResourcesSeeder extends Seeder { async shouldRun() { // eslint-disable-line class-methods-use-this return Resource.count().exec().then(count => count === 0); } async run() { // eslint-disable-line class-methods-use-this let result; await SeedingHelper.readData('resourceActions') .then((resourceActionsData) => { const machinesId = ObjectId(); const actionTest1 = ObjectId(resourceActionsData.find(x => x.name === 'test1')._id); const actionTest2 = ObjectId(resourceActionsData.find(x => x.name === 'test2')._id); const data = [ { _id: machinesId, name: 'machines', actions: [ actionTest1, actionTest2, ], }, ]; result = Resource.create(data); if (result) SeedingHelper.saveData('resources', data); }); return result; } } module.exports = ResourcesSeeder; 对并将它们转换为列表:

Int

然而,GHC抱怨说

import Control.Monad (forM, forM_)
import Data.Function (on)
import Data.List     (nub)

main = do
    t <- readLn
    forM_ [1..t] (\_ -> do
        n <- readLn
        points <- forM [1..n] (\_ -> do
            pointStr <- getLine
            let [x, y] = map read $ words pointStr
            return (x, y))
        putStrLn $ if check points then "YES" else "NO")

check :: [(Int, Int)] -> Bool
check points = ((==) `on` length) (nub $ map fst points) points

我试图在 • Couldn't match type ‘(Int, Int)’ with ‘Int’ Expected type: [Int] Actual type: [(Int, Int)] • In the second argument of ‘(==) `on` length’, namely ‘points’ In the expression: ((==) `on` length) (nub $ map fst points) points In an equation for ‘check’: check points = ((==) `on` length) (nub $ map fst points) points | 16 | check points = ((==) `on` length) (nub $ map fst points) points | ^^^^^^ 周围添加一个类型声明,但这也不起作用。如果我将read替换为return (x, y),我会收到同样的错误。似乎GHC将return x视为(x, y),而不是Int

任何帮助?

2 个答案:

答案 0 :(得分:3)

您的问题不在于形成列表 - 错误显示第16行,这是检查功能。看着那里,我们看到:

check :: [(Int, Int)] -> Bool
check points = ((==) `on` length) (nub $ map fst points) points

注意你的相等函数的类型:

((==) `on` length) :: Foldable t => t a -> t a -> Bool

所以你需要提供两个相同类型的参数(高级注释:on需要使用RankNTypes来允许长度应用于不同类型的参数)。但是,您提供了两种不同类型的参数([Int][(Int,Int)])。不要试图变得花哨,只是做可读的解决方案:

length (nub (map fst points)) == length points

答案 1 :(得分:1)

错误消息告诉您问题出在check,而不在main中(特别是,它不与read或{{1}有关})。更具体地说,它表示类型不匹配发生在return的第二个参数中。既然如此,最好先了解(==) `on` length的类型:

(==) `on` length

这告诉我们两个列表必须具有相同的元素类型,而GHCi> :t (==) `on` length (==) `on` length :: Foldable t => t a -> t a -> Bool - ergo&#34;无法与check类型匹配(Int, Int)&#34 ;. Int接受单个任意投影函数(在您的情况下为on),因此可以确保投影可以应用于两个参数的唯一方法是它们是否具有相同的类型: / p>

length

类型系统无法利用这样一个事实:在您的特定情况下,GHCi> :t on on :: (b -> b -> c) -> (a -> b) -> a -> a -> c 可以应用于列表而不管元素类型如何,因此参数类型之间的差异是无关紧要的

解决这一困难的最简单方法是放弃length

on

或者,您可以在双方都应用check points = length (nub (map fst points)) == length points - 元素值除了map fst之外没有关系,所以它没有区别

nub

实现相同效果的更明确的方法是使用check points = ((==) `on` length) (nub xCoords) xCoords where xCoords = map fst points 中的void,可以用来丢弃列表元素:

Data.Functor

最后,可以选择完全切换到不同的算法。这使得改进成为可能:check points = ((==) `on` length) (void . nub $ map fst points) (void points) 可以通过仅运行最短列表而不是两者来执行(如使用check两次要求)。你可能想要实现它。为了便于说明,这是一个利用These, the exclusive disjunction type provided by the these package的奇特解决方案。

length

import Data.List (nub) import Data.Align (align) import Data.These (isThese) check :: Eq a => [(a, b)] -> Bool check pairs = null . dropWhile isThese $ align (nub . map fst $ pairs) pairs 可以简洁地描述为贪婪的align。如需额外评论,请参阅Does Haskell have a greedy zip (one preserving all elements)?